home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1995 November / PCWK1195.iso / inne / win95 / sieciowe / hotja32.lzh / hotjava / classsrc / browser / audio / audioplayer.java < prev    next >
Text File  |  1995-08-11  |  12KB  |  405 lines

  1. /*
  2.  * @(#)AudioPlayer.java    1.21 95/07/11 Arthur van Hoff
  3.  *
  4.  * Copyright (c) 1994 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software
  7.  * and its documentation for NON-COMMERCIAL purposes and without
  8.  * fee is hereby granted provided that this copyright notice
  9.  * appears in all copies. Please refer to the file "copyright.html"
  10.  * for further important copyright and licensing information.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  13.  * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  14.  * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  15.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  16.  * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  17.  * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  18.  */
  19.  
  20. package browser.audio;
  21.  
  22. import java.util.Vector;
  23. import java.util.Enumeration;
  24. import java.util.Linker;
  25. import java.io.InputStream;
  26. import java.io.OutputStream;
  27. import java.io.FileOutputStream;
  28.  
  29. /**
  30.  * This classprovides an interface to play multiple
  31.  * channels of 8 bit ulaw encoded, 8000hz, single channel audio.
  32.  * Note that it provides a temporary and very Solaris
  33.  * specific solution, the APIs are likely to change when this
  34.  * is generalize to work on different platforms.<p>
  35.  * To play an audio stream use:
  36.  * <pre>
  37.  *    AudioPlayer.player.start(audiostream);
  38.  * </pre>
  39.  * To stop playing an audio stream use:
  40.  * <pre>
  41.  *    AudioPlayer.player.stop(audiostream);
  42.  * </pre>
  43.  * To play an audio stream from a URL use:
  44.  * <pre>
  45.  *    AudioStream audiostream = new AudioStream(url.openStream());
  46.  *    AudioPlayer.player.start(audiostream);
  47.  * </pre>
  48.  * To play a continuous sound you first have to
  49.  * create an AudioData instance and use it to construct a
  50.  * ContinuousAudioDataStream.
  51.  * For example:
  52.  * <pre>
  53.  *    AudoData data = new AudioStream(url.openStream()).getData();
  54.  *    ContinuousAudioDataStream audiostream = new ContinuousAudioDataStream(data);
  55.  *    AudioPlayer.player.stop(audiostream);
  56.  * </pre>
  57.  *
  58.  * @see AudioData
  59.  * @see AudioDataStream
  60.  * @see AudioStream
  61.  * @see AudioStreamSequence
  62.  * @see ContinuousAudioDataStream
  63.  * @author Arthur van Hoff
  64.  * @version     1.21, 11 Jul 1995
  65.  */
  66. public
  67. class AudioPlayer extends Thread {
  68.     private static final int MSCLICK = 40;
  69.     private static final int MSMARGIN = MSCLICK / 3;
  70.     private static final int SAMPLE_RATE = 8000;
  71.     private static final int BYTES_PER_SAMPLE = 1;
  72.  
  73.     private int dev;
  74.     private Vector streams;
  75.     private byte ulaw[];
  76.     private int linear[];
  77.  
  78.     /**
  79.      * The default audio player. This audio player is initialized
  80.      * automatically.
  81.      */
  82.     public static final AudioPlayer player = new AudioPlayer();
  83.  
  84.     /*
  85.      * ulaw stuff
  86.      */
  87.  
  88.     /* define the add-in bias for 16 bit samples */
  89.     private final static int ULAW_BIAS = 0x84;
  90.     private final static int ULAW_CLIP = 32635;
  91.  
  92.     private final static int ULAW_TAB[] = {
  93.     -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
  94.     -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
  95.     -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
  96.     -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
  97.     -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
  98.     -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
  99.     -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
  100.     -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
  101.     -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
  102.     -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
  103.     -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
  104.     -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
  105.     -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
  106.     -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
  107.     -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
  108.     -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
  109.     32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
  110.     23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
  111.     15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
  112.     11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
  113.     7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
  114.     5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
  115.     3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
  116.     2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
  117.     1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
  118.     1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
  119.     876,    844,    812,    780,    748,    716,    684,    652,
  120.     620,    588,    556,    524,    492,    460,    428,    396,
  121.     372,    356,    340,    324,    308,    292,    276,    260,
  122.     244,    228,    212,    196,    180,    164,    148,    132,
  123.     120,    112,    104,     96,     88,     80,     72,     64,
  124.         56,     48,     40,     32,     24,     16,      8,      0
  125.     };
  126.     private final static int ULAW_LUT[] = {
  127.     0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  128.     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  129.     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  130.     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  131.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  132.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  133.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  134.     6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  135.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  136.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  137.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  138.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  139.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  140.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  141.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  142.     7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  143.     };
  144.  
  145.     /**
  146.      * Construct an AudioPlayer.
  147.      */
  148.     private AudioPlayer() {
  149.     super("Audio Player");
  150.         try {
  151.         Linker.loadLibrary("mmedia");
  152.         } catch (UnsatisfiedLinkException e) {
  153.             System.out.println("could not find/load the mmedia library");
  154.         }
  155.     int bufferSize = ((SAMPLE_RATE * MSCLICK) / 1000) * BYTES_PER_SAMPLE;
  156.     ulaw = new byte[bufferSize];
  157.     linear = new int[bufferSize];
  158.     streams = new Vector();
  159.     setPriority(MAX_PRIORITY);
  160.     setDaemon(true);
  161.     start();
  162.     }
  163.  
  164.     /**
  165.      * Start playing a stream. The stream will continue to play
  166.      * until the stream runs out of data, or it is stopped.
  167.      * @see AudioPlayer#stop
  168.      */
  169.     public synchronized void start(InputStream in) {
  170.     if (streams != null) {
  171.         streams.insertElementAt(in, 0);
  172.         notify();
  173.     } else {
  174.         in.close();
  175.     }
  176.     }
  177.  
  178.     /**
  179.      * Stop playing a stream. The stream will stop playing,
  180.      * nothing happens if the stream wasn't playing in the
  181.      * first place.
  182.      * @see AudioPlayer#start
  183.      */
  184.     public synchronized void stop(InputStream in) {
  185.     if (streams != null) {
  186.         if (streams.removeElement(in)) {
  187.         in.close();
  188.         }
  189.     }
  190.     }
  191.  
  192.     private native int audioOpen();
  193.     private native void audioClose();
  194.     private synchronized native void audioWrite(byte buf[], int len);
  195.  
  196.     /**
  197.      * Open the device (done automatically)
  198.      */
  199.     private synchronized void open() {
  200.     int    ntries = 1;
  201.     int    maxtries = 5;
  202.     while (dev == 0) {
  203.         dev = audioOpen();
  204.         if (dev < 0) {
  205.         System.out.println("no audio device");
  206.         return;
  207.         }
  208.         if (dev == 0) {
  209.         System.out.println("audio device busy (attempt " + ntries + " out of " + maxtries + ")");
  210.         if ((streams.size() == 0) || (++ntries > maxtries)) {
  211.             // failed to open the device
  212.             // close all open streams, wait a while and return
  213.             closeStreams();
  214.             return;
  215.         }
  216.  
  217.         // use wait instead of sleep because this unlocks the
  218.         // current object during the wait.
  219.         wait(3000);
  220.         }
  221.     }
  222.     }
  223.  
  224.     /**
  225.      * Close the device (done automatically)
  226.      */
  227.     private synchronized void close() {
  228.     if (dev != 0) {
  229.         audioClose();
  230.         dev = 0;
  231.     }
  232.     }
  233.  
  234.     /**
  235.      * Mix one click of data
  236.      */
  237.     private synchronized void mix() {
  238.     //System.out.println("MIX " + ulaw.length + " buffer");
  239.     int len = ulaw.length;
  240.     byte ubuf[] = ulaw;
  241.  
  242.     switch (streams.size()) {
  243.       case 0: {
  244.         // fill the buffer with silence
  245.         for (int n = len ; n-- > 0 ;) {
  246.         ubuf[n] = 127;
  247.         }
  248.         break;
  249.       }
  250.  
  251.       case 1: {
  252.         // read from the input stream
  253.         InputStream in = (InputStream)streams.elementAt(0);
  254.         int n = in.read(ubuf, 0, len);
  255.         if (n <= 0) {
  256.         streams.removeElementAt(0);
  257.         //System.out.println("remove " + "0");
  258.         in.close();
  259.         n = 0;
  260.         } 
  261.         // fill the rest of the buffer with silence
  262.         for (; n < len ; n++) {
  263.         ubuf[n] = 127;
  264.         }
  265.         break;
  266.       }
  267.  
  268.       default: {
  269.         int tab[] = ULAW_TAB;
  270.         int lbuf[] = linear;
  271.         int i = streams.size() - 1;
  272.  
  273.         // fill linear buffer with the first stream
  274.         InputStream in = (InputStream)streams.elementAt(i);
  275.         int n = in.read(ubuf, 0, len);
  276.         if (n > 0) {
  277.         for (int j = 0 ; j < n ; j++) {
  278.             lbuf[j] = tab[ubuf[j] & 0xFF];
  279.         }
  280.         for (; n < len ; n++) {
  281.             lbuf[n] = 0;
  282.         }
  283.         } else {
  284.         streams.removeElementAt(i);
  285.         in.close();
  286.         //System.out.println("remove " + i);
  287.         }
  288.  
  289.         // mix the rest of the streams into the linear buffer
  290.         while (i-- > 0) {
  291.         in = (InputStream)streams.elementAt(i);
  292.         n = in.read(ubuf, 0, len);
  293.         if (n > 0) {
  294.             while (n-- > 0) {
  295.             lbuf[n] += tab[ubuf[n] & 0xFF];
  296.             }
  297.         } else {
  298.             streams.removeElementAt(i);
  299.             in.close();
  300.             //System.out.println("remove " + i);
  301.         }
  302.         }
  303.  
  304.         // convert the linear buffer back to ulaw
  305.         int lut[] = ULAW_LUT;
  306.         for (n = len ; n-- > 0 ; ) {
  307.         int sample = lbuf[n];
  308.  
  309.         /* Get the sample into sign-magnitude. */
  310.         if (sample >= 0) {
  311.             if (sample > ULAW_CLIP) {
  312.             sample = ULAW_CLIP;    /* clip the magnitude */
  313.             }
  314.            
  315.             /* Convert from 16 bit linear to ulaw. */
  316.             sample += ULAW_BIAS;
  317.             int exponent = lut[sample >> 7];
  318.             int mantissa = (sample >> (exponent + 3)) & 0x0F;
  319.             sample = ((exponent << 4) | mantissa) ^ 0xFF;
  320.         } else {
  321.             sample = -sample;
  322.             if (sample > ULAW_CLIP) {
  323.             sample = ULAW_CLIP;    /* clip the magnitude */
  324.             }
  325.             
  326.             /* Convert from 16 bit linear to ulaw. */
  327.             sample += ULAW_BIAS;
  328.             int exponent = lut[sample >> 7];
  329.             int mantissa = (sample >> (exponent + 3)) & 0x0F;
  330.             sample = ((exponent << 4) | mantissa) ^ 0x7F;
  331.         }
  332.         ubuf[n] = (byte)sample;
  333.         }
  334.       }
  335.     }
  336.     }
  337.  
  338.     /**
  339.      * Wait for data
  340.      */
  341.     private synchronized void waitForData() {
  342.     close();
  343.     wait();
  344.     open();
  345.     }
  346.  
  347.     /**
  348.      * Close streams
  349.      */
  350.     private synchronized void closeStreams() {
  351.     // close the streams be garbage collected
  352.     for (Enumeration e = streams.elements() ; e.hasMoreElements() ; ) {
  353.         ((InputStream)e.nextElement()).close();
  354.     }
  355.     streams = new Vector();
  356.     }
  357.  
  358.     /**
  359.      * Main mixing loop. This is called automatically when the AudioPlayer
  360.      * is created.
  361.      */
  362.     public void run() {
  363.     //System.out.println("run");
  364.     if (streams.size() == 0) {
  365.         waitForData();
  366.     }
  367.     open();
  368.     mix();
  369.     int tm = System.nowMillis() - MSMARGIN;
  370.  
  371.     while (dev >= 0) {
  372.         //int adjust = System.nowMillis() - tm;
  373.         //System.out.println("adjust = " + adjust);
  374.         audioWrite(ulaw, ulaw.length);
  375.         
  376.         if (streams.size() == 0) {
  377.         // wait for more data
  378.         waitForData();
  379.         mix();
  380.         tm = System.nowMillis() - MSMARGIN;
  381.         } else {
  382.         // mix the next bit
  383.         mix();
  384.  
  385.         // wait for the time out
  386.         tm += MSCLICK;
  387.         int delay = tm - System.nowMillis();
  388.         if (delay > 0) {
  389.             //System.out.println("delay1=" + delay);
  390.             sleep(delay);
  391.         } else {
  392.             // We've lost it, reset the time..
  393.             //System.out.println("delay2=" + delay);
  394.             tm = System.nowMillis() - MSMARGIN;
  395.         }
  396.         }
  397.     }
  398.  
  399.     // close streams and exit
  400.     closeStreams();
  401.     streams = null;
  402.     System.out.println("audio player exit");
  403.     }
  404. }
  405.