svn commit: r7016 - trunk/src/net/java/sip/communicator/impl/neomedia: device jmfext/media/protocol/portaudio jmfext/media/renderer/audio portaudio...

lubomir_m at dev.java.net lubomir_m at dev.java.net
Tue Apr 20 09:21:06 CEST 2010


Author: lubomir_m
Date: 2010-04-20 07:21:04+0000
New Revision: 7016

Modified:
   trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java
   trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java
   trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java
   trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
   trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java
   trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java

Log:
Cleans up a tiny bit a few PortAudio-related classes, adds/fixes some Javadocs and reports the time stamp of the audio data closer to its capturing. Anyway, there should be nothing noticeable at runtime.

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/device/AudioMediaDeviceSession.java	2010-04-20 07:21:04+0000
@@ -138,23 +138,6 @@
     }
 
     /**
-     * Sets the  <tt>SimpleAudioLevelListener</tt> that this session should be
-     * notifying about changes in local audio level related information. This
-     * class only supports a single listener for audio changes per source
-     * (i.e. stream or data source). Audio changes are generally quite time
-     * intensive (~ 50 per second) so we are doing this in order to reduce the
-     * number of objects associated with the process (such as event instances
-     * listener list iterators and sync copies).
-     *
-     * @param listener the <tt>SimpleAudioLevelListener</tt> to add
-     */
-    public void setLocalUserAudioLevelListener(
-                                            SimpleAudioLevelListener listener)
-    {
-        this.localUserAudioLevelEffect.setAudioLevelListener(listener);
-    }
-
-    /**
      * Creates an audio level effect and add its to the codec chain of the
      * <tt>TrackControl</tt> assuming that it only contains a single track.
      *
@@ -163,7 +146,7 @@
      * effects.
      */
     private void registerLocalUserAudioLevelJMFEffect(TrackControl tc)
-            throws UnsupportedPlugInException
+        throws UnsupportedPlugInException
     {
         //we register the effect regardless of whether or not we have any
         //listeners at this point because we won't get a second chance.
@@ -173,25 +156,7 @@
         //XXX: i am assuming that a single effect could be reused multiple times
         // if that turns out not to be the case we need to create a new instance
         // here.
-        tc.setCodecChain(new Codec[]{localUserAudioLevelEffect});
-    }
-
-    /**
-     * Sets <tt>listener</tt> as the <tt>SimpleAudioLevelListener</tt> that we
-     * are going to notify every time a change occurs in the audio level of
-     * the media that this device session is receiving from the remote party.
-     * This class only supports a single listener for audio changes per source
-     * (i.e. stream or data source). Audio changes are generally quite time
-     * intensive (~ 50 per second) so we are doing this in order to reduce the
-     * number of objects associated with the process (such as event instances
-     * listener list iterators and sync copies).
-     *
-     * @param listener the <tt>SimpleAudioLevelListener</tt> that we want
-     * notified for audio level changes in the remote participant's media.
-     */
-    public void setStreamAudioLevelListener(SimpleAudioLevelListener listener)
-    {
-        this.streamAudioLevelEffect.setAudioLevelListener(listener);
+        tc.setCodecChain(new Codec[] { localUserAudioLevelEffect });
     }
 
     /**
@@ -214,7 +179,42 @@
         //however the effect would do next to nothing unless we register a
         //first listener with it.
         // Assume there is only one audio track
-        trackControl.setCodecChain(new Codec[]{streamAudioLevelEffect});
+        trackControl.setCodecChain(new Codec[] { streamAudioLevelEffect });
+    }
+
+    /**
+     * Sets the  <tt>SimpleAudioLevelListener</tt> that this session should be
+     * notifying about changes in local audio level related information. This
+     * class only supports a single listener for audio changes per source
+     * (i.e. stream or data source). Audio changes are generally quite time
+     * intensive (~ 50 per second) so we are doing this in order to reduce the
+     * number of objects associated with the process (such as event instances
+     * listener list iterators and sync copies).
+     *
+     * @param listener the <tt>SimpleAudioLevelListener</tt> to add
+     */
+    public void setLocalUserAudioLevelListener(
+                                            SimpleAudioLevelListener listener)
+    {
+        this.localUserAudioLevelEffect.setAudioLevelListener(listener);
+    }
+
+    /**
+     * Sets <tt>listener</tt> as the <tt>SimpleAudioLevelListener</tt> that we
+     * are going to notify every time a change occurs in the audio level of
+     * the media that this device session is receiving from the remote party.
+     * This class only supports a single listener for audio changes per source
+     * (i.e. stream or data source). Audio changes are generally quite time
+     * intensive (~ 50 per second) so we are doing this in order to reduce the
+     * number of objects associated with the process (such as event instances
+     * listener list iterators and sync copies).
+     *
+     * @param listener the <tt>SimpleAudioLevelListener</tt> that we want
+     * notified for audio level changes in the remote participant's media.
+     */
+    public void setStreamAudioLevelListener(SimpleAudioLevelListener listener)
+    {
+        this.streamAudioLevelEffect.setAudioLevelListener(listener);
     }
 
     /**

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DSAudioStream.java	2010-04-20 07:21:04+0000
@@ -56,8 +56,13 @@
         {
             AudioFormat audioFormat = DataSource.getCaptureFormat();
 
-            stream = PortAudioManager.getInstance().getInputStream(deviceIndex,
-                audioFormat.getSampleRate(), audioFormat.getChannels());
+            stream
+                = PortAudioManager
+                    .getInstance()
+                        .getInputStream(
+                            deviceIndex,
+                            audioFormat.getSampleRate(),
+                            audioFormat.getChannels());
         }
 
         stream.start();
@@ -93,31 +98,27 @@
         throws IOException
     {
         if (stream == null)
+        {
+            buffer.setLength(0);
             return;
+        }
 
         try
         {
-            byte[] bytebuff = stream.read();
-
-            buffer.setTimeStamp(System.nanoTime());
-
-            buffer.setData(bytebuff);
-            buffer.setLength(bytebuff.length);
-
-            buffer.setFlags(Buffer.FLAG_SYSTEM_TIME);
-            buffer.setFormat(getFormat());
-            buffer.setHeader(null);
-
-            buffer.setSequenceNumber(seqNo);
-            seqNo++;
+            stream.read(buffer);
         }
-        catch (PortAudioException pae)
+        catch (PortAudioException paex)
         {
-            IOException ioe = new IOException();
+            IOException ioex = new IOException();
 
-            ioe.initCause(pae);
-            throw ioe;
+            ioex.initCause(paex);
+            throw ioex;
         }
+
+        buffer.setFormat(getFormat());
+        buffer.setHeader(null);
+
+        buffer.setSequenceNumber(seqNo++);
     }
 
     /**

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/protocol/portaudio/DataSource.java	2010-04-20 07:21:04+0000
@@ -55,10 +55,7 @@
      * for this <tt>DataSource</tt>.
      */
     private final Object[] controls
-        = new Object[]
-                {
-                    new FormatControlImpl()
-                };
+        = new Object[] { new FormatControlImpl() };
 
     /**
      * Indicates whether the datasource is starteded or not.

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java	2010-04-20 07:21:04+0000
@@ -15,7 +15,7 @@
 import net.java.sip.communicator.util.*;
 
 /**
- * PortAudio renderer.
+ * Implements an audio <tt>Renderer</tt> which uses PortAudio.
  *
  * @author Damian Minkov
  * @author Lubomir Marinov
@@ -25,110 +25,125 @@
     implements Renderer
 {
     /**
-     * logger
+     * The <tt>Logger</tt> used by the <tt>PortAudioRenderer</tt> class and its
+     * instances for logging output.
      */
-    private static final Logger logger =
-        Logger.getLogger(PortAudioRenderer.class);
+    private static final Logger logger
+        = Logger.getLogger(PortAudioRenderer.class);
 
     /**
-     * Name of the renderer.
+     * The human-readable name of the <tt>PortAudioRenderer</tt> JMF plug-in.
      */
-    private static final String name = "PortAudio Renderer";
+    private static final String PLUGIN_NAME = "PortAudio Renderer";
 
     /**
-     * The supported input formats. The input formats are
-     * changed after the device is set.
+     * The list of the standard sample rates supported by
+     * <tt>PortAudioRenderer</tt>.
      */
-    public static Format[] supportedInputFormats = new Format[]{};
+    private static final double[] SUPPORTED_SAMPLE_RATES
+        = new double[] { 8000, 16000, 22050, 44100, 48000 };
 
     /**
-     * The standard supported sample rates.
+     * The PortAudio index of the device to be used by the
+     * <tt>PortAudioRenderer</tt> instance which are to be opened.
      */
-    private static double[] supportedSampleRates =
-        new double[]{8000, 16000, 22050, 44100, 48000};
-
-    /**
-     * The current input format of the renderer.
-     */
-    private AudioFormat inputFormat;
+    private static int deviceIndex = -1;
 
     /**
-     * PortAudio output stream currently in use.
+     * The supported input formats. Changed when {@link #deviceIndex} is set.
      */
-    private OutputPortAudioStream stream = null;
+    public static Format[] supportedInputFormats = new Format[0];
 
     /**
-     * Is renderer started.
+     * The JMF <tt>Format</tt> in which this <tt>PortAudioRenderer</tt> is
+     * currently configured to read the audio data to be rendered.
      */
-    boolean started = false;
+    private AudioFormat inputFormat = null;
 
     /**
-     * Index of the device we use and must use when creating stream.
+     * The output PortAudio stream represented by this instance.
      */
-    private static int deviceIndex = -1;
+    private OutputPortAudioStream stream = null;
 
     /**
-     * Lists the input formats supported by this Renderer.
-     * @return  An array of Format objects that represent
-     *          the input formats supported by this Renderer.
+     *  Closes the plug-in.
      */
-    public Format[] getSupportedInputFormats()
+    public void close()
     {
-        return supportedInputFormats;
+        if (stream != null)
+        {
+            stop();
+
+            try
+            {
+                stream.close();
+            }
+            catch (PortAudioException paex)
+            {
+                logger.error("Failed to close stream", paex);
+            }
+        }
     }
 
     /**
-     * Sets the Format of the input data.
-     * @param format the format to set.
-     * @return The Format that was set.
+     * Gets the descriptive/human-readble name of this JMF plug-in.
+     *
+     * @return the descriptive/human-readable name of this JMF plug-in
      */
-    public Format setInputFormat(Format format)
+    public String getName()
     {
-        if(!(format instanceof AudioFormat))
-            return null;
-
-        this.inputFormat = (AudioFormat) format;
-
-        return inputFormat;
+        return PLUGIN_NAME;
     }
 
     /**
-     * Initiates the rendering process.
-     * When start is called, the renderer begins rendering
-     * any data available in its internal buffers.
+     * Gets the list of JMF <tt>Format</tt>s of audio data which this
+     * <tt>Renderer</tt> is capable of rendering.
+     *
+     * @return an array of JMF <tt>Format</tt>s of audio data which this
+     * <tt>Renderer</tt> is capable of rendering
      */
-    public void start()
+    public Format[] getSupportedInputFormats()
     {
-        try
-        {
-            stream.start();
-        }
-        catch (PortAudioException paex)
-        {
-            logger.error("Starting portaudio stream failed", paex);
-        }
+        return supportedInputFormats;
     }
 
     /**
-     * Halts the rendering process.
+     * Opens the PortAudio device and output stream represented by this instance
+     * which are to be used to render audio.
+     *
+     * @throws ResourceUnavailableException if the PortAudio device or output
+     * stream cannot be created or opened
      */
-    public void stop()
+    public void open()
+        throws ResourceUnavailableException
     {
-        try
-        {
-            stream.stop();
-        }
-        catch (PortAudioException paex)
+        if (stream == null)
         {
-            logger.error("Closing portaudio stream failed", paex);
+            try
+            {
+                stream
+                    = PortAudioManager
+                        .getInstance()
+                            .getOutputStream(
+                                deviceIndex,
+                                inputFormat.getSampleRate(),
+                                inputFormat.getChannels());
+            }
+            catch (PortAudioException paex)
+            {
+                throw new ResourceUnavailableException(paex.getMessage());
+            }
         }
     }
 
     /**
-     * Processes the data and renders it
-     * to the output device represented by this Renderer.
-     * @param buffer the input data.
-     * @return BUFFER_PROCESSED_OK if the processing is successful.
+     * Renders the audio data contained in a specific <tt>Buffer</tt> onto the
+     * PortAudio device represented by this <tt>Renderer</tt>.
+     *
+     * @param buffer the <tt>Buffer</tt> which contains the audio data to be
+     * rendered
+     * @return <tt>BUFFER_PROCESSED_OK</tt> if the specified <tt>buffer</tt> has
+     * been successfully processed
      */
     public int process(Buffer buffer)
     {
@@ -144,101 +159,96 @@
         {
             logger.error("Error writing to device", paex);
         }
-
         return BUFFER_PROCESSED_OK;
     }
 
     /**
-     * Returns the name of this plug-in.
-     * @return a <tt>String</tt> which contains the descriptive name of this
-     * plug-in.
+     * Resets the state of the plug-in.
      */
-    public String getName()
+    public void reset()
     {
-        return name;
     }
 
     /**
-     * Opens the device and stream that we will use to render data.
-     * @throws  ResourceUnavailableException If required resources cannot
-     *          be opened/created.
+     * Sets the PortAudio index of the device to be used by the
+     * <tt>PortAudioRenderer</tt> instances which are to be opened later on.
+     * Changes the <tt>supportedInputFormats</tt> property of all
+     * <tt>PortAudioRenderer</tt> instances.
+     *
+     * @param locator the <tt>MediaLocator</tt> specifying the PortAudio device
+     * index
      */
-    public void open()
-        throws ResourceUnavailableException
+    public static void setDevice(MediaLocator locator)
     {
-        if (stream == null)
-            try
-            {
-                stream
-                    = PortAudioManager
-                        .getInstance()
-                            .getOutputStream(
-                                deviceIndex,
-                                inputFormat.getSampleRate(),
-                                inputFormat.getChannels());
-            }
-            catch (PortAudioException e)
-            {
-                throw new ResourceUnavailableException(e.getMessage());
-            }
+        deviceIndex = PortAudioUtils.getDeviceIndexFromLocator(locator);
+
+        int outputChannels = 1;
+
+        supportedInputFormats = new Format[SUPPORTED_SAMPLE_RATES.length];
+        for(int i = 0; i < SUPPORTED_SAMPLE_RATES.length; i++)
+        {
+            supportedInputFormats[i]
+                = new AudioFormat(
+                        AudioFormat.LINEAR,
+                        SUPPORTED_SAMPLE_RATES[i],
+                        16,
+                        outputChannels,
+                        AudioFormat.LITTLE_ENDIAN,
+                        AudioFormat.SIGNED,
+                        16,
+                        Format.NOT_SPECIFIED,
+                        Format.byteArray);
+        }
     }
 
     /**
-     *  Closes the plug-in.
+     * Sets the JMF <tt>Format</tt> of the audio data to be rendered by this
+     * <tt>Renderer</tt>.
+     *
+     * @param format the JMF <tt>Format</tt> of the audio data to be redered by
+     * this instance
+     * @return <tt>null</tt> if the specified <tt>format</tt> is not compatible
+     * with this <tt>Renderer</tt>; otherwise, the JMF <tt>Format</tt> which has
+     * been successfully set
      */
-    public void close()
+    public Format setInputFormat(Format format)
     {
-        if (stream != null)
-        {
-            stop();
+        if(!(format instanceof AudioFormat))
+            return null;
 
-            try
-            {
-                stream.close();
-            }
-            catch (PortAudioException paex)
-            {
-                logger.error("Failed to close stream", paex);
-            }
-        }
+        this.inputFormat = (AudioFormat) format;
+        return this.inputFormat;
     }
 
     /**
-     * Resets the state of the plug-in.
+     * Starts the rendering process. Any audio data available in the internal
+     * resources associated with this <tt>PortAudioRenderer</tt> will begin
+     * being rendered.
      */
-    public void reset()
+    public void start()
     {
+        try
+        {
+            stream.start();
+        }
+        catch (PortAudioException paex)
+        {
+            logger.error("Starting PortAudio stream failed", paex);
+        }
     }
 
     /**
-     * Used to set the device index used by the renderer common for all
-     * instances of it. Change the format corresponding the device which
-     * will be used.
-     * @param locator the locator containing the device index.
+     * Stops the rendering process.
      */
-    public static void setDevice(MediaLocator locator)
+    public void stop()
     {
-        deviceIndex = PortAudioUtils.getDeviceIndexFromLocator(locator);
-
-        int outputChannels = 1;
-
-        supportedInputFormats = new Format[supportedSampleRates.length];
-
-        for(int i = 0; i < supportedSampleRates.length; i++)
+        try
         {
-            double sampleRate = supportedSampleRates[i];
-
-            supportedInputFormats[i] =
-                new AudioFormat(
-                    AudioFormat.LINEAR,
-                      sampleRate,
-                      16,
-                      outputChannels,
-                      AudioFormat.LITTLE_ENDIAN,
-                      AudioFormat.SIGNED,
-                      16,
-                      Format.NOT_SPECIFIED,
-                      Format.byteArray);
+            stream.stop();
+        }
+        catch (PortAudioException paex)
+        {
+            logger.error("Closing PortAudio stream failed", paex);
         }
     }
 }

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/InputPortAudioStream.java	2010-04-20 07:21:04+0000
@@ -6,15 +6,38 @@
  */
 package net.java.sip.communicator.impl.neomedia.portaudio.streams;
 
+import javax.media.*;
+
 import net.java.sip.communicator.impl.neomedia.portaudio.*;
 
 /**
  * The input audio stream.
  *
  * @author Damian Minkov
+ * @author Lubomir Marinov
  */
 public class InputPortAudioStream
 {
+
+    /**
+     * The audio data to be read from this <tt>InputPortAudioStream</tt> upon
+     * the next {@link #read(Buffer)} request.
+     */
+    private byte[] bufferData = null;
+
+    /**
+     * The number of bytes in {@link #bufferData} which represent valid audio
+     * data to be read from this <tt>InputPortAudioStream</tt> upon the next
+     * {@link #read(Buffer)} request.
+     */
+    private int bufferLength = 0;
+
+    /**
+     * The time stamp of the audio data in {@link #bufferData} represented in
+     * accord with {@link Buffer#FLAG_SYSTEM_TIME}.
+     */
+    private long bufferTimeStamp = 0;
+
     /**
      * Our parent stream, the actual source of data.
      */
@@ -34,46 +57,86 @@
     private boolean stopping = false;
 
     /**
-     * The buffer to return.
-     */
-    protected byte[] buffer = null;
-
-    /**
      * Creates new input stream (slave) with master input stream.
-     * @param st the parent(master) input stream.
+     *
+     * @param parentStream the parent/master input stream.
      */
-    public InputPortAudioStream(MasterPortAudioStream st)
+    public InputPortAudioStream(MasterPortAudioStream parentStream)
     {
-        this.parentStream = st;
+        this.parentStream = parentStream;
     }
 
     /**
-     * Block and read a buffer from the stream if there is no buffer.
+     * Reads audio data from this <tt>InputPortAudioStream</tt> into a specific
+     * <tt>Buffer</tt> blocking until audio data is indeed available.
      *
-     * @return the bytes that a read from underlying stream.
-     * @throws PortAudioException if an error occurs while reading.
+     * @param buffer the <tt>Buffer</tt> into which the audio data read from
+     * this <tt>InputPortAudioStream</tt> is to be returned
+     * @throws PortAudioException if an error occurs while reading
      */
-    public byte[] read()
+    public void read(Buffer buffer)
         throws PortAudioException
     {
-        if(stopping || !started)
-            return new byte[0];
+        if (stopping || !started)
+        {
+            buffer.setLength(0);
+            return;
+        }
 
-        synchronized(parentStream)
+        synchronized (parentStream)
         {
-            byte[] res = buffer;
+            if (bufferData == null)
+            {
+                parentStream.read(buffer);
+            }
+            else
+            {
+                buffer.setData(bufferData);
+                buffer.setFlags(Buffer.FLAG_SYSTEM_TIME);
+                buffer.setLength(bufferLength);
+                buffer.setOffset(0);
+                buffer.setTimeStamp(bufferTimeStamp);
+            }
+
+            /*
+             * The bufferData of this InputPortAudioStream has been consumed so
+             * make sure a new piece of audio data will be read the next time.
+             */
+            bufferData = null;
+        }
+    }
 
-            if(res == null)
-                res = parentStream.read();
-            buffer = null;
-            return res;
+    /**
+     * Sets the audio data to be read from this <tt>InputPortAudioStream</tt>
+     * upon the next request. Used by {@link #parentStream} in order to provide
+     * all audio samples to all its slaves and not only to the one which caused
+     * the actual read from PortAudio.
+     *
+     * @param bufferData the audio data to be read from this
+     * <tt>InputPortAudioStream</tt> upon the next request
+     * @param bufferLength the number of bytes in <tt>bufferData</tt> which
+     * represent valid audio data to be read from this
+     * <tt>InputPortAudioStream</tt> upon the next request
+     * @param bufferTimeStamp the time stamp of the audio data in
+     * <tt>bufferData</tt> represented in accord with
+     * {@link Buffer#FLAG_SYSTEM_TIME}
+     */
+    void setBuffer(byte[] bufferData, int bufferLength, long bufferTimeStamp)
+    {
+        synchronized (parentStream)
+        {
+            this.bufferData = bufferData;
+            this.bufferLength = bufferLength;
+            this.bufferTimeStamp = bufferTimeStamp;
         }
     }
 
     /**
      * Starts the stream. Also starts the parent stream
      * if its not already started.
-     * @throws PortAudioException if stream cannot be started.
+     *
+     * @throws PortAudioException if an error occurs while starting this
+     * <tt>InputPortAudioStream</tt>
      */
     public synchronized void start()
         throws PortAudioException
@@ -88,7 +151,9 @@
     /**
      * Stops the stream. Also stops the parent if we are the last slave
      * stream that use it.
-     * @throws PortAudioException
+     *
+     * @throws PortAudioException if an error occurs while stopping this
+     * <tt>InputPortAudioStream</tt>
      */
     public synchronized void stop()
         throws PortAudioException
@@ -101,17 +166,4 @@
             stopping = false;
         }
     }
-
-    /**
-     * The parent can set a buffer that was requested and read by other
-     * slave stream.
-     * @param buffer the buffer to set.
-     */
-    public void setBuffer(byte[] buffer)
-    {
-        synchronized (parentStream)
-        {
-            this.buffer = buffer;
-        }
-    }
 }

Modified: trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java
Url: https://sip-communicator.dev.java.net/source/browse/sip-communicator/trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java?view=diff&rev=7016&p1=trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java&p2=trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java&r1=7015&r2=7016
==============================================================================
--- trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java	(original)
+++ trunk/src/net/java/sip/communicator/impl/neomedia/portaudio/streams/MasterPortAudioStream.java	2010-04-20 07:21:04+0000
@@ -8,6 +8,8 @@
 
 import java.util.*;
 
+import javax.media.*;
+
 import net.java.sip.communicator.impl.neomedia.portaudio.*;
 
 /**
@@ -26,14 +28,23 @@
     private int deviceIndex = -1;
 
     /**
-     * The stream pointer we are using or 0 if stopped and not initialized.
+     * The number of bytes to read from a native PortAudio stream in a single
+     * invocation. Based on {@link #framesPerBuffer} and {@link #frameSize}.
      */
-    private long stream = 0;
+    private final int bytesPerBuffer;
 
     /**
-     * Whether this stream is started.
+     * The number of channel for the current stream.
      */
-    private boolean started = false;
+    private int channels;
+
+    /**
+     * This is the output stream which is connected to the current input stream.
+     * When using echo cancellation its the actual output stream, otherwise its
+     * just a non null object. Need to synch closing stream in order to avoid
+     * concurrency: using the output stream(in Pa_ReadStream) while closing it.
+     */
+    private Object connectedToStreamSync = new Object();
 
     /**
      * The frame size we use.
@@ -47,35 +58,26 @@
     private final int framesPerBuffer;
 
     /**
-     * The number of bytes to read from a native PortAudio stream in a single
-     * invocation. Based on {@link #framesPerBuffer} and {@link #frameSize}.
-     */
-    private final int bytesPerBuffer;
-
-    /**
      * The sample rate for the current stream.
      */
     private double sampleRate;
 
     /**
-     * The number of channel for the current stream.
+     * The <tt>InputPortAudioStream</tt>s which read audio from this
+     * <tt>MasterPortAudioStream</tt>s.
      */
-    private int channels;
+    private final List<InputPortAudioStream> slaves
+        = new ArrayList<InputPortAudioStream>();
 
     /**
-     * This is the output stream which is connected to the current input stream.
-     * When using echo cancellation its the actual output stream, otherwise its
-     * just a non null object. Need to synch closing stream in order to avoid
-     * concurrency: using the output stream(in Pa_ReadStream) while closing it.
+     * Whether this stream is started.
      */
-    private Object connectedToStreamSync = new Object();
+    private boolean started = false;
 
     /**
-     * The <tt>InputPortAudioStream</tt>s which read audio from this
-     * <tt>MasterPortAudioStream</tt>s.
+     * The stream pointer we are using or 0 if stopped and not initialized.
      */
-    private final List<InputPortAudioStream> slaves
-        = new ArrayList<InputPortAudioStream>();
+    private long stream = 0;
 
     /**
      * Creates new stream.
@@ -85,7 +87,7 @@
      * @throws PortAudioException if stream cannot be opened.
      */
     public MasterPortAudioStream(
-        int deviceIndex, double sampleRate, int channels)
+            int deviceIndex, double sampleRate, int channels)
         throws PortAudioException
     {
         this.deviceIndex = deviceIndex;
@@ -102,6 +104,24 @@
     }
 
     /**
+     * Returns the index of the device that we use.
+     * @return the deviceIndex
+     */
+    public int getDeviceIndex()
+    {
+        return deviceIndex;
+    }
+
+    /**
+     * Returns the pointer to the stream that we use for reading.
+     * @return the stream pointer.
+     */
+    public long getStream()
+    {
+        return stream;
+    }
+
+    /**
      * Create the stream.
      * @throws PortAudioException if stream cannot be opened.
      */
@@ -125,6 +145,79 @@
     }
 
     /**
+     * Reads audio data from this <tt>MasterPortAudioStream</tt> into a specific
+     * <tt>Buffer</tt> blocking until audio data is indeed available.
+     *
+     * @param buffer the <tt>Buffer</tt> into which the audio data read from
+     * this <tt>MasterPortAudioStream</tt> is to be returned
+     * @throws PortAudioException if an error occurs while reading
+     */
+    public synchronized void read(Buffer buffer)
+        throws PortAudioException
+    {
+        if (!started)
+        {
+            buffer.setLength(0);
+            return;
+        }
+
+        /*
+         * Attempting to reuse the data of the specified buffer in order to
+         * decrease the unnecessary allocations is not currently implemented.
+         */
+        int bufferLength = bytesPerBuffer;
+        byte[] bufferData = new byte[bufferLength];
+
+        synchronized (connectedToStreamSync)
+        {
+            PortAudio.Pa_ReadStream(stream, bufferData, framesPerBuffer);
+        }
+
+        long bufferTimeStamp = System.nanoTime();
+
+        buffer.setData(bufferData);
+        buffer.setFlags(Buffer.FLAG_SYSTEM_TIME);
+        buffer.setLength(bufferLength);
+        buffer.setOffset(0);
+        buffer.setTimeStamp(bufferTimeStamp);
+
+        int slaveCount = slaves.size();
+
+        for(int slaveIndex = 0; slaveIndex < slaveCount; slaveIndex++)
+        {
+            slaves
+                .get(slaveIndex)
+                    .setBuffer(bufferData, bufferLength, bufferTimeStamp);
+        }
+    }
+
+    /**
+     * Sets parameters to the underlying stream.
+     * @param out the connected output stream if echo cancel is enabled.
+     * @param deNoiseEnabled true if we want to enable noise reduction.
+     * @param echoCancelEnabled true to enable echo cancel.
+     * @param frameSize Number of samples to process at one time
+     *        (should correspond to 10-20 ms).
+     * @param filterLength Number of samples of echo to cancel
+     *        (should generally correspond to 100-500 ms)
+     */
+    public void setParams(OutputPortAudioStream out,
+        boolean deNoiseEnabled,
+        boolean echoCancelEnabled, int frameSize, int filterLength)
+    {
+        if(out != null)
+            this.connectedToStreamSync = out.getCloseSyncObject();
+
+        long outStream = (out == null) ? 0 : out.getStream();
+
+        PortAudio.setEchoCancelParams(
+            stream,
+            outStream,
+            deNoiseEnabled,
+            echoCancelEnabled, frameSize, filterLength);
+    }
+
+    /**
      * Starts this <tt>MasterPortAudioStream</tt> so that a specific
      * <tt>InputPortAudioStream</tt> can read from it. When the first such
      * <tt>InputPortAudioStream</tt> request the starting of this instance, this
@@ -144,11 +237,12 @@
         if(slaves.isEmpty())
         {
             if(stream == 0)
+            {
                 initStream();
-
-            // if still not initted return
-            if(stream == 0)
-                return;
+                // if still not initted return
+                if(stream == 0)
+                    return;
+            }
 
             // start
             PortAudio.Pa_StartStream(stream);
@@ -186,75 +280,4 @@
             PortAudioManager.getInstance().stoppedInputPortAudioStream(this);
         }
     }
-
-    /**
-     * Returns the index of the device that we use.
-     * @return the deviceIndex
-     */
-    public int getDeviceIndex()
-    {
-        return deviceIndex;
-    }
-
-    /**
-     * Returns the pointer to the stream that we use for reading.
-     * @return the stream pointer.
-     */
-    public long getStream()
-    {
-        return stream;
-    }
-
-    /**
-     * Block and read a buffer from the stream.
-     *
-     * @return the bytes that a read from underlying stream.
-     * @throws PortAudioException if an error occurs while reading.
-     */
-    public synchronized byte[] read()
-        throws PortAudioException
-    {
-        if(!started)
-            return new byte[0];
-
-        byte[] bytebuff = new byte[bytesPerBuffer];
-
-        synchronized(connectedToStreamSync)
-        {
-                PortAudio.Pa_ReadStream(stream, bytebuff, framesPerBuffer);
-        }
-
-        for(InputPortAudioStream slave : slaves)
-            slave.setBuffer(bytebuff);
-
-        return bytebuff;
-    }
-
-    /**
-     * Sets parameters to the underlying stream.
-     * @param out the connected output stream if echo cancel is enabled.
-     * @param deNoiseEnabled true if we want to enable noise reduction.
-     * @param echoCancelEnabled true to enable echo cancel.
-     * @param frameSize Number of samples to process at one time
-     *        (should correspond to 10-20 ms).
-     * @param filterLength Number of samples of echo to cancel
-     *        (should generally correspond to 100-500 ms)
-     */
-    public void setParams(OutputPortAudioStream out,
-        boolean deNoiseEnabled,
-        boolean echoCancelEnabled, int frameSize, int filterLength)
-    {
-        if(out != null)
-        {
-            this.connectedToStreamSync = out.getCloseSyncObject();
-        }
-
-        long outStream = (out == null) ? 0 : out.getStream();
-
-        PortAudio.setEchoCancelParams(
-            stream,
-            outStream,
-            deNoiseEnabled,
-            echoCancelEnabled, frameSize, filterLength);
-    }
 }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe at sip-communicator.dev.java.net
For additional commands, e-mail: commits-help at sip-communicator.dev.java.net





More information about the commits mailing list