From fad4b65f6f71cc31b1fab262e3c85b96bb00b2bf Mon Sep 17 00:00:00 2001
From: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Mon, 3 Jun 2013 13:30:57 +0300
Subject: [PATCH] Improves AudioMixer for one-to-one calls, strives towards
 pass-through behavior.

---
 src/org/jitsi/impl/neomedia/ArrayIOUtils.java |   85 +-
 .../codec/audio/speex/SpeexResampler.java     |   23 +-
 .../impl/neomedia/conference/AudioMixer.java  |  778 ++++++------
 .../AudioMixerPushBufferStream.java           | 1129 ++++++++---------
 .../AudioMixingPushBufferDataSource.java      |  202 ++-
 .../AudioMixingPushBufferStream.java          |  296 ++---
 .../neomedia/conference/DataSourceFilter.java |    3 +-
 ...aSourceDesc.java => InDataSourceDesc.java} |  157 ++-
 ...InputStreamDesc.java => InStreamDesc.java} |   42 +-
 .../neomedia/conference/IntArrayCache.java    |   96 ++
 .../neomedia/device/AudioMediaDeviceImpl.java |    4 +-
 .../device/AudioMixerMediaDevice.java         |   10 +-
 .../neomedia/device/MediaDeviceSession.java   |    2 -
 .../service/neomedia/DTMFInbandTone.java      |  215 ++--
 14 files changed, 1507 insertions(+), 1535 deletions(-)
 rename src/org/jitsi/impl/neomedia/conference/{InputDataSourceDesc.java => InDataSourceDesc.java} (71%)
 rename src/org/jitsi/impl/neomedia/conference/{InputStreamDesc.java => InStreamDesc.java} (78%)
 create mode 100644 src/org/jitsi/impl/neomedia/conference/IntArrayCache.java

diff --git a/src/org/jitsi/impl/neomedia/ArrayIOUtils.java b/src/org/jitsi/impl/neomedia/ArrayIOUtils.java
index dceda9da..1416e58b 100644
--- a/src/org/jitsi/impl/neomedia/ArrayIOUtils.java
+++ b/src/org/jitsi/impl/neomedia/ArrayIOUtils.java
@@ -15,6 +15,25 @@
 public class ArrayIOUtils
 {
 
+    /**
+     * Reads an integer from a specific series of bytes starting the reading at
+     * a specific offset in it.
+     *
+     * @param in the series of bytes to read an integer from
+     * @param inOffset the offset in <tt>in</tt> at which the reading of the
+     * integer is to start
+     * @return an integer read from the specified series of bytes starting at
+     * the specified offset in it
+     */
+    public static int readInt(byte[] in, int inOffset)
+    {
+        return
+            (in[inOffset + 3] << 24)
+                | ((in[inOffset + 2] & 0xFF) << 16)
+                | ((in[inOffset + 1] & 0xFF) << 8)
+                | (in[inOffset] & 0xFF);
+    }
+
     /**
      * Reads a short integer from a specific series of bytes starting the
      * reading at a specific offset in it. The difference with
@@ -22,33 +41,49 @@ public class ArrayIOUtils
      * <tt>int</tt> which has been formed by reading two bytes, not a
      * <tt>short</tt>.
      *
-     * @param input the series of bytes to read the short integer from
-     * @param inputOffset the offset in <tt>input</tt> at which the reading of
-     * the short integer is to start
+     * @param in the series of bytes to read the short integer from
+     * @param inOffset the offset in <tt>in</tt> at which the reading of the
+     * short integer is to start
      * @return a short integer in the form of <tt>int</tt> read from the
      * specified series of bytes starting at the specified offset in it
      */
-    public static int readInt16(byte[] input, int inputOffset)
+    public static int readInt16(byte[] in, int inOffset)
     {
-        return ((input[inputOffset + 1] << 8) | (input[inputOffset] & 0x00FF));
+        return ((in[inOffset + 1] << 8) | (in[inOffset] & 0x00FF));
     }
 
     /**
      * Reads a short integer from a specific series of bytes starting the
      * reading at a specific offset in it.
      *
-     * @param input the series of bytes to read the short integer from
-     * @param inputOffset the offset in <tt>input</tt> at which the reading of
-     * the short integer is to start
+     * @param in the series of bytes to read the short integer from
+     * @param inOffset the offset in <tt>in</tt> at which the reading of the
+     * short integer is to start
      * @return a short integer in the form of <tt>short</tt> read from the
      * specified series of bytes starting at the specified offset in it
      */
-    public static short readShort(byte[] input, int inputOffset)
+    public static short readShort(byte[] in, int inOffset)
     {
-        return
-            (short)
-                ((input[inputOffset + 1] << 8)
-                    | (input[inputOffset] & 0x00FF));
+        return (short) ((in[inOffset + 1] << 8) | (in[inOffset] & 0x00FF));
+    }
+
+    /**
+     * Converts an integer to a series of bytes and writes the result into a
+     * specific output array of bytes starting the writing at a specific offset
+     * in it.
+     *
+     * @param in the integer to be written out as a series of bytes
+     * @param out the output to receive the conversion of the specified
+     * integer to a series of bytes
+     * @param outOffset the offset in <tt>out</tt> at which the writing of the
+     * result of the conversion is to be started
+     */
+    public static void writeInt(int in, byte[] out, int outOffset)
+    {
+        out[outOffset] = (byte) (in & 0xFF);
+        out[outOffset + 1] = (byte) ((in >>> 8) & 0xFF);
+        out[outOffset + 2] = (byte) ((in >>> 16) & 0xFF);
+        out[outOffset + 3] = (byte) (in >> 24);
     }
 
     /**
@@ -58,18 +93,18 @@ public static short readShort(byte[] input, int inputOffset)
      * is that the input is an <tt>int</tt> and just two bytes of it are
      * written.
      *
-     * @param input the short integer to be written out as a series of bytes
+     * @param in the short integer to be written out as a series of bytes
      * specified as an integer i.e. the value to be converted is contained in
      * only two of the four bytes made available by the integer
-     * @param output the output to receive the conversion of the specified short
+     * @param out the output to receive the conversion of the specified short
      * integer to a series of bytes
-     * @param outputOffset the offset in <tt>output</tt> at which the writing of
-     * the result of the conversion is to be started
+     * @param outOffset the offset in <tt>out</tt> at which the writing of the
+     * result of the conversion is to be started
      */
-    public static void writeInt16(int input, byte[] output, int outputOffset)
+    public static void writeInt16(int in, byte[] out, int outOffset)
     {
-        output[outputOffset] = (byte) (input & 0xFF);
-        output[outputOffset + 1] = (byte) (input >> 8);
+        out[outOffset] = (byte) (in & 0xFF);
+        out[outOffset + 1] = (byte) (in >> 8);
     }
 
     /**
@@ -77,15 +112,15 @@ public static void writeInt16(int input, byte[] output, int outputOffset)
      * a specific output array of bytes starting the writing at a specific
      * offset in it.
      *
-     * @param input the short integer to be written out as a series of bytes
+     * @param in the short integer to be written out as a series of bytes
      * specified as <tt>short</tt>
-     * @param output the output to receive the conversion of the specified short
+     * @param out the output to receive the conversion of the specified short
      * integer to a series of bytes
-     * @param outputOffset the offset in <tt>output</tt> at which the writing of
+     * @param outOffset the offset in <tt>out</tt> at which the writing of
      * the result of the conversion is to be started
      */
-    public static void writeShort(short input, byte[] output, int outputOffset)
+    public static void writeShort(short in, byte[] out, int outOffset)
     {
-        writeInt16(input, output, outputOffset);
+        writeInt16(in, out, outOffset);
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/codec/audio/speex/SpeexResampler.java b/src/org/jitsi/impl/neomedia/codec/audio/speex/SpeexResampler.java
index 75c6c3c4..d9cae165 100644
--- a/src/org/jitsi/impl/neomedia/codec/audio/speex/SpeexResampler.java
+++ b/src/org/jitsi/impl/neomedia/codec/audio/speex/SpeexResampler.java
@@ -326,7 +326,7 @@ protected int doProcess(Buffer inBuffer, Buffer outBuffer)
             if (resampler == 0)
                 return BUFFER_PROCESSED_FAILED;
 
-            byte[] input = (byte[]) inBuffer.getData();
+            byte[] in = (byte[]) inBuffer.getData();
             int inLength = inBuffer.getLength();
             int frameSize
                 = channels * (inAudioFormat.getSampleSizeInBits() / 8);
@@ -337,17 +337,26 @@ protected int doProcess(Buffer inBuffer, Buffer outBuffer)
              */
             int inSampleCount = inLength / frameSize;
             int outSampleCount = (inSampleCount * outSampleRate) / inSampleRate;
-            byte[] output
+            byte[] out
                 = validateByteArraySize(
                         outBuffer,
                         outSampleCount * frameSize,
                         false);
 
-            outSampleCount
-                = Speex.speex_resampler_process_interleaved_int(
-                        resampler,
-                        input, inBuffer.getOffset(), inSampleCount,
-                        output, 0, outSampleCount);
+            /*
+             * XXX The method Speex.speex_resampler_process_interleaved_int will
+             * crash if in is null.
+             */
+            if (inSampleCount == 0)
+                outSampleCount = 0;
+            else
+            {
+                outSampleCount
+                    = Speex.speex_resampler_process_interleaved_int(
+                            resampler,
+                            in, inBuffer.getOffset(), inSampleCount,
+                            out, 0, outSampleCount);
+            }
             outBuffer.setFormat(outAudioFormat);
             outBuffer.setLength(outSampleCount * frameSize);
             outBuffer.setOffset(0);
diff --git a/src/org/jitsi/impl/neomedia/conference/AudioMixer.java b/src/org/jitsi/impl/neomedia/conference/AudioMixer.java
index b8f073cb..0ccdef4d 100644
--- a/src/org/jitsi/impl/neomedia/conference/AudioMixer.java
+++ b/src/org/jitsi/impl/neomedia/conference/AudioMixer.java
@@ -21,7 +21,6 @@
 import org.jitsi.impl.neomedia.device.*;
 import org.jitsi.impl.neomedia.protocol.*;
 import org.jitsi.util.*;
-// disambiguation
 
 /**
  * Represents an audio mixer which manages the mixing of multiple audio streams
@@ -29,7 +28,7 @@
  * multiple input audio streams.
  * <p>
  * The input audio streams are provided to the <tt>AudioMixer</tt> through
- * {@link #addInputDataSource(DataSource)} in the form of input
+ * {@link #addInDataSource(DataSource)} in the form of input
  * <tt>DataSource</tt>s giving access to one or more input
  * <tt>SourceStreams</tt>.
  * </p>
@@ -38,22 +37,16 @@
  * streams is provided by the <tt>AudioMixer</tt> in the form of a
  * <tt>AudioMixingPushBufferDataSource</tt> giving access to a
  * <tt>AudioMixingPushBufferStream</tt>. Such an output is obtained through
- * {@link #createOutputDataSource()}. The <tt>AudioMixer</tt> is able to provide
+ * {@link #createOutDataSource()}. The <tt>AudioMixer</tt> is able to provide
  * multiple output audio streams at one and the same time, though, each of them
  * containing the mix of a subset of the input audio streams.
  * </p>
  *
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
  */
 public class AudioMixer
 {
 
-    /**
-     * The <tt>Logger</tt> used by the <tt>AudioMixer</tt> class and its
-     * instances for logging output.
-     */
-    private static final Logger logger = Logger.getLogger(AudioMixer.class);
-
     /**
      * The default output <tt>AudioFormat</tt> in which <tt>AudioMixer</tt>,
      * <tt>AudioMixingPushBufferDataSource</tt> and
@@ -68,6 +61,48 @@ public class AudioMixer
                 AudioFormat.LITTLE_ENDIAN,
                 AudioFormat.SIGNED);
 
+    /**
+     * The <tt>Logger</tt> used by the <tt>AudioMixer</tt> class and its
+     * instances for logging output.
+     */
+    private static final Logger logger = Logger.getLogger(AudioMixer.class);
+
+    /**
+     * Gets the <tt>Format</tt> in which a specific <tt>DataSource</tt>
+     * provides stream data.
+     *
+     * @param dataSource the <tt>DataSource</tt> for which the <tt>Format</tt>
+     * in which it provides stream data is to be determined
+     * @return the <tt>Format</tt> in which the specified <tt>dataSource</tt>
+     * provides stream data if it was determined; otherwise, <tt>null</tt>
+     */
+    private static Format getFormat(DataSource dataSource)
+    {
+        FormatControl formatControl
+            = (FormatControl)
+                dataSource.getControl(FormatControl.class.getName());
+
+        return (formatControl == null) ? null : formatControl.getFormat();
+    }
+
+    /**
+     * Gets the <tt>Format</tt> in which a specific <tt>SourceStream</tt>
+     * provides data.
+     *
+     * @param stream the <tt>SourceStream</tt> for which the <tt>Format</tt> in
+     * which it provides data is to be determined
+     * @return the <tt>Format</tt> in which the specified <tt>SourceStream</tt>
+     * provides data if it was determined; otherwise, <tt>null</tt>
+     */
+    private static Format getFormat(SourceStream stream)
+    {
+        if (stream instanceof PushBufferStream)
+            return ((PushBufferStream) stream).getFormat();
+        if (stream instanceof PullBufferStream)
+            return ((PullBufferStream) stream).getFormat();
+        return null;
+    }
+
     /**
      * The <tt>BufferControl</tt> of this instance and, respectively, its
      * <tt>AudioMixingPushBufferDataSource</tt>s.
@@ -97,15 +132,28 @@ public class AudioMixer
      * The collection of input <tt>DataSource</tt>s this instance reads audio
      * data from.
      */
-    private final List<InputDataSourceDesc> inputDataSources
-        = new ArrayList<InputDataSourceDesc>();
+    private final List<InDataSourceDesc> inDataSources
+        = new ArrayList<InDataSourceDesc>();
+
+    /**
+     * The cache of <tt>int</tt> arrays utilized by this instance for the
+     * purposes of reducing garbage collection.
+     */
+    final IntArrayCache intArrayCache = new IntArrayCache();
 
     /**
      * The <tt>AudioMixingPushBufferDataSource</tt> which contains the mix of
-     * <tt>inputDataSources</tt> excluding <tt>captureDevice</tt> and is thus
+     * <tt>inDataSources</tt> excluding <tt>captureDevice</tt> and is thus
      * meant for playback on the local peer in a call.
      */
-    private final AudioMixingPushBufferDataSource localOutputDataSource;
+    private final AudioMixingPushBufferDataSource localOutDataSource;
+
+    /**
+     * The output <tt>AudioMixerPushBufferStream</tt> through which this
+     * instance pushes audio sample data to
+     * <tt>AudioMixingPushBufferStream</tt>s to be mixed.
+     */
+    private AudioMixerPushBufferStream outStream;
 
     /**
      * The number of output <tt>AudioMixingPushBufferDataSource</tt>s reading
@@ -115,13 +163,6 @@ public class AudioMixer
      */
     private int started;
 
-    /**
-     * The output <tt>AudioMixerPushBufferStream</tt> through which this
-     * instance pushes audio sample data to
-     * <tt>AudioMixingPushBufferStream</tt>s to be mixed.
-     */
-    private AudioMixerPushBufferStream outputStream;
-
     /**
      * Initializes a new <tt>AudioMixer</tt> instance. Because JMF's
      * <tt>Manager.createMergingDataSource(DataSource[])</tt> requires the
@@ -162,10 +203,10 @@ public AudioMixer(CaptureDevice captureDevice)
 
         this.captureDevice = captureDevice;
 
-        this.localOutputDataSource = createOutputDataSource();
-        addInputDataSource(
-            (DataSource) this.captureDevice,
-            this.localOutputDataSource);
+        this.localOutDataSource = createOutDataSource();
+        addInDataSource(
+                (DataSource) this.captureDevice,
+                this.localOutDataSource);
     }
 
     /**
@@ -174,12 +215,12 @@ public AudioMixer(CaptureDevice captureDevice)
      * specified <tt>DataSource</tt> indeed provides audio, the respective
      * contributions to the mix are always included.
      *
-     * @param inputDataSource a new <tt>DataSource</tt> to input audio to this
+     * @param inDataSource a new <tt>DataSource</tt> to input audio to this
      * instance
      */
-    public void addInputDataSource(DataSource inputDataSource)
+    public void addInDataSource(DataSource inDataSource)
     {
-        addInputDataSource(inputDataSource, null);
+        addInDataSource(inDataSource, null);
     }
 
     /**
@@ -189,30 +230,30 @@ public void addInputDataSource(DataSource inputDataSource)
      * contributions to the mix will be excluded from the mix output provided
      * through a specific <tt>AudioMixingPushBufferDataSource</tt>.
      *
-     * @param inputDataSource a new <tt>DataSource</tt> to input audio to this
+     * @param inDataSource a new <tt>DataSource</tt> to input audio to this
      * instance
-     * @param outputDataSource the <tt>AudioMixingPushBufferDataSource</tt> to
-     * not include the audio contributions of <tt>inputDataSource</tt> in the
+     * @param outDataSource the <tt>AudioMixingPushBufferDataSource</tt> to
+     * not include the audio contributions of <tt>inDataSource</tt> in the
      * mix it outputs
      */
-    void addInputDataSource(
-            DataSource inputDataSource,
-            AudioMixingPushBufferDataSource outputDataSource)
+    void addInDataSource(
+            DataSource inDataSource,
+            AudioMixingPushBufferDataSource outDataSource)
     {
-        if (inputDataSource == null)
-            throw new NullPointerException("inputDataSource");
+        if (inDataSource == null)
+            throw new NullPointerException("inDataSource");
 
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
-                if (inputDataSource.equals(inputDataSourceDesc.inputDataSource))
-                    throw new IllegalArgumentException("inputDataSource");
+            for (InDataSourceDesc inDataSourceDesc : inDataSources)
+                if (inDataSource.equals(inDataSourceDesc.inDataSource))
+                    throw new IllegalArgumentException("inDataSource");
 
-            InputDataSourceDesc inputDataSourceDesc
-                = new InputDataSourceDesc(
-                        inputDataSource,
-                        outputDataSource);
-            boolean added = inputDataSources.add(inputDataSourceDesc);
+            InDataSourceDesc inDataSourceDesc
+                = new InDataSourceDesc(
+                        inDataSource,
+                        outDataSource);
+            boolean added = inDataSources.add(inDataSourceDesc);
 
             if (added)
             {
@@ -220,18 +261,18 @@ void addInputDataSource(
                 {
                     logger.trace(
                             "Added input DataSource with hashCode "
-                                + inputDataSource.hashCode());
+                                + inDataSource.hashCode());
                 }
 
                 /*
-                 * If the other inputDataSources have already been connected,
+                 * If the other inDataSources have already been connected,
                  * connect to the new one as well.
                  */
                 if (connected > 0)
                 {
                     try
                     {
-                        inputDataSourceDesc.connect(this);
+                        inDataSourceDesc.connect(this);
                     }
                     catch (IOException ioex)
                     {
@@ -239,19 +280,19 @@ void addInputDataSource(
                     }
                 }
 
-                // Update outputStream with any new inputStreams.
-                if (outputStream != null)
-                    getOutputStream();
+                // Update outStream with any new inStreams.
+                if (outStream != null)
+                    getOutStream();
 
                 /*
-                 * If the other inputDataSources have been started, start the
+                 * If the other inDataSources have been started, start the
                  * new one as well.
                  */
                 if (started > 0)
                 {
                     try
                     {
-                        inputDataSourceDesc.start();
+                        inDataSourceDesc.start();
                     }
                     catch (IOException ioe)
                     {
@@ -275,24 +316,21 @@ void addInputDataSource(
     void connect()
         throws IOException
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
             if (connected == 0)
             {
-                for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
+                for (InDataSourceDesc inDataSourceDesc : inDataSources)
                     try
                     {
-                        inputDataSourceDesc.connect(this);
+                        inDataSourceDesc.connect(this);
                     }
                     catch (IOException ioe)
                     {
-                        logger
-                            .error(
-                                "Failed to connect to inputDataSource "
-                                    + MediaStreamImpl
-                                        .toString(
-                                            inputDataSourceDesc
-                                                .inputDataSource),
+                        logger.error(
+                                "Failed to connect to inDataSource "
+                                    + MediaStreamImpl.toString(
+                                            inDataSourceDesc.inDataSource),
                                 ioe);
                         throw ioe;
                     }
@@ -304,8 +342,8 @@ void connect()
                  * bufferLength may change so make sure that the bufferLengths
                  * of the input streams are equal.
                  */
-                if (outputStream != null)
-                    outputStream.equalizeInputStreamBufferLength();
+                if (outStream != null)
+                    outStream.equalizeInStreamBufferLength();
             }
 
             connected++;
@@ -321,12 +359,12 @@ void connect()
      * <tt>DataSource</tt> added to this instance.
      *
      * @param dataSource the <tt>DataSource</tt> to connect to
-     * @param inputDataSource the <tt>DataSource</tt> which is the cause for
+     * @param inDataSource the <tt>DataSource</tt> which is the cause for
      * <tt>dataSource</tt> to exist in this <tt>AudioMixer</tt>
      * @throws IOException if anything wrong happens while connecting to
      * <tt>dataSource</tt>
      */
-    protected void connect(DataSource dataSource, DataSource inputDataSource)
+    protected void connect(DataSource dataSource, DataSource inDataSource)
         throws IOException
     {
         dataSource.connect();
@@ -339,44 +377,44 @@ protected void connect(DataSource dataSource, DataSource inputDataSource)
      * in a separate thread as are, for example, input <tt>DataSource</tt>s
      * which are being transcoded.
      *
-     * @param inputDataSource the <tt>InputDataSourceDesc</tt> of the input
+     * @param inDataSource the <tt>InDataSourceDesc</tt> of the input
      * <tt>DataSource</tt> which has finished its connecting procedure
      * @throws IOException if anything wrong happens while including
-     * <tt>inputDataSource</tt> into the mix
+     * <tt>inDataSource</tt> into the mix
      */
-    void connected(InputDataSourceDesc inputDataSource)
+    void connected(InDataSourceDesc inDataSource)
         throws IOException
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            if (inputDataSources.contains(inputDataSource)
+            if (inDataSources.contains(inDataSource)
                     && (connected > 0))
             {
                 if (started > 0)
-                    inputDataSource.start();
-                if (outputStream != null)
-                    getOutputStream();
+                    inDataSource.start();
+                if (outStream != null)
+                    getOutStream();
             }
         }
     }
 
     /**
-     * Creates a new <tt>InputStreamDesc</tt> instance which is to describe a
+     * Creates a new <tt>InStreamDesc</tt> instance which is to describe a
      * specific input <tt>SourceStream</tt> originating from a specific input
-     * <tt>DataSource</tt> given by its <tt>InputDataSourceDesc</tt>.
+     * <tt>DataSource</tt> given by its <tt>InDataSourceDesc</tt>.
      *
-     * @param inputStream the input <tt>SourceStream</tt> to be described by the
+     * @param inStream the input <tt>SourceStream</tt> to be described by the
      * new instance
-     * @param inputDataSourceDesc the input <tt>DataSource</tt> given by its
-     * <tt>InputDataSourceDesc</tt> to be described by the new instance
-     * @return a new <tt>InputStreamDesc</tt> instance which describes the
+     * @param inDataSourceDesc the input <tt>DataSource</tt> given by its
+     * <tt>InDataSourceDesc</tt> to be described by the new instance
+     * @return a new <tt>InStreamDesc</tt> instance which describes the
      * specified input <tt>SourceStream</tt> and <tt>DataSource</tt>
      */
-    private InputStreamDesc createInputStreamDesc(
-            SourceStream inputStream,
-            InputDataSourceDesc inputDataSourceDesc)
+    private InStreamDesc createInStreamDesc(
+            SourceStream inStream,
+            InDataSourceDesc inDataSourceDesc)
     {
-        return new InputStreamDesc(inputStream, inputDataSourceDesc);
+        return new InStreamDesc(inStream, inDataSourceDesc);
     }
 
     /**
@@ -393,7 +431,7 @@ private InputStreamDesc createInputStreamDesc(
      * to a single audio stream representing the mix of the audio streams input
      * into this <tt>AudioMixer</tt> through its input <tt>DataSource</tt>s
      */
-    public AudioMixingPushBufferDataSource createOutputDataSource()
+    public AudioMixingPushBufferDataSource createOutDataSource()
     {
         return new AudioMixingPushBufferDataSource(this);
     }
@@ -403,28 +441,28 @@ public AudioMixingPushBufferDataSource createOutputDataSource()
      * specific input <tt>DataSource</tt> into a specific output
      * <tt>Format</tt>.
      *
-     * @param inputDataSourceDesc the <tt>InputDataSourceDesc</tt> describing
+     * @param inDataSourceDesc the <tt>InDataSourceDesc</tt> describing
      * the input <tt>DataSource</tt> to be transcoded into the specified output
      * <tt>Format</tt> and to receive the transcoding <tt>DataSource</tt>
-     * @param outputFormat the <tt>Format</tt> in which the tracks of the input
+     * @param outFormat the <tt>Format</tt> in which the tracks of the input
      * <tt>DataSource</tt> are to be transcoded
      * @return <tt>true</tt> if a new transcoding <tt>DataSource</tt> has been
      * created for the input <tt>DataSource</tt> described by
-     * <tt>inputDataSourceDesc</tt>; otherwise, <tt>false</tt>
+     * <tt>inDataSourceDesc</tt>; otherwise, <tt>false</tt>
      * @throws IOException if an error occurs while creating the transcoding
      * <tt>DataSource</tt>, connecting to it or staring it
      */
     private boolean createTranscodingDataSource(
-            InputDataSourceDesc inputDataSourceDesc,
-            Format outputFormat)
+            InDataSourceDesc inDataSourceDesc,
+            Format outFormat)
         throws IOException
     {
-        if (inputDataSourceDesc.createTranscodingDataSource(outputFormat))
+        if (inDataSourceDesc.createTranscodingDataSource(outFormat))
         {
             if (connected > 0)
-                inputDataSourceDesc.connect(this);
+                inDataSourceDesc.connect(this);
             if (started > 0)
-                inputDataSourceDesc.start();
+                inDataSourceDesc.start();
             return true;
         }
         else
@@ -441,7 +479,7 @@ private boolean createTranscodingDataSource(
      */
     void disconnect()
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
             if (connected <= 0)
                 return;
@@ -450,16 +488,16 @@ void disconnect()
 
             if (connected == 0)
             {
-                for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
-                    inputDataSourceDesc.disconnect();
+                for (InDataSourceDesc inDataSourceDesc : inDataSources)
+                    inDataSourceDesc.disconnect();
 
                 /*
-                 * XXX Make the outputStream to release the inputStreams.
+                 * XXX Make the outStream to release the inStreams.
                  * Otherwise, the PushBufferStream ones which have been wrapped
                  * into CachingPushBufferStream may remaing waiting.
                  */
-                outputStream.setInputStreams(null);
-                outputStream = null;
+                outStream.setInStreams(null);
+                outStream = null;
             }
         }
     }
@@ -479,8 +517,8 @@ BufferControl getBufferControl()
         {
             BufferControl captureDeviceBufferControl
                 = (BufferControl)
-                    ((Controls) captureDevice)
-                        .getControl(BufferControl.class.getName());
+                    ((Controls) captureDevice).getControl(
+                            BufferControl.class.getName());
 
             if (captureDeviceBufferControl != null)
                 bufferControl
@@ -514,50 +552,6 @@ String getContentType()
         return ContentDescriptor.RAW;
     }
 
-    /**
-     * Gets an <tt>InputStreamDesc</tt> from a specific existing list of
-     * <tt>InputStreamDesc</tt>s which describes a specific
-     * <tt>SourceStream</tt>. If such an <tt>InputStreamDesc</tt> does not
-     * exist, returns <tt>null</tt>.
-     *
-     * @param inputStream the <tt>SourceStream</tt> to locate an
-     * <tt>InputStreamDesc</tt> for in <tt>existingInputStreamDescs</tt>
-     * @param existingInputStreamDescs the list of existing
-     * <tt>InputStreamDesc</tt>s in which an <tt>InputStreamDesc</tt> for
-     * <tt>inputStream</tt> is to be located
-     * @return an <tt>InputStreamDesc</tt> from
-     * <tt>existingInputStreamDescs</tt> which describes <tt>inputStream</tt> if
-     * such an <tt>InputStreamDesc</tt> exists; otherwise, <tt>null</tt>
-     */
-    private InputStreamDesc getExistingInputStreamDesc(
-            SourceStream inputStream,
-            InputStreamDesc[] existingInputStreamDescs)
-    {
-        if (existingInputStreamDescs == null)
-            return null;
-
-        for (InputStreamDesc existingInputStreamDesc
-                : existingInputStreamDescs)
-        {
-            SourceStream existingInputStream
-                = existingInputStreamDesc.getInputStream();
-
-            if (existingInputStream == inputStream)
-                return existingInputStreamDesc;
-            if ((existingInputStream instanceof BufferStreamAdapter<?>)
-                    && (((BufferStreamAdapter<?>) existingInputStream)
-                                .getStream()
-                            == inputStream))
-                return existingInputStreamDesc;
-            if ((existingInputStream instanceof CachingPushBufferStream)
-                    && (((CachingPushBufferStream) existingInputStream)
-                                .getStream()
-                            == inputStream))
-                return existingInputStreamDesc;
-        }
-        return null;
-    }
-
     /**
      * Gets the duration of each one of the output streams produced by this
      * <tt>AudioMixer</tt>.
@@ -571,41 +565,44 @@ Time getDuration()
     }
 
     /**
-     * Gets the <tt>Format</tt> in which a specific <tt>DataSource</tt>
-     * provides stream data.
+     * Gets an <tt>InStreamDesc</tt> from a specific existing list of
+     * <tt>InStreamDesc</tt>s which describes a specific
+     * <tt>SourceStream</tt>. If such an <tt>InStreamDesc</tt> does not
+     * exist, returns <tt>null</tt>.
      *
-     * @param dataSource the <tt>DataSource</tt> for which the <tt>Format</tt>
-     * in which it provides stream data is to be determined
-     * @return the <tt>Format</tt> in which the specified <tt>dataSource</tt>
-     * provides stream data if it was determined; otherwise, <tt>null</tt>
+     * @param inStream the <tt>SourceStream</tt> to locate an
+     * <tt>InStreamDesc</tt> for in <tt>existingInStreamDescs</tt>
+     * @param existingInStreamDescs the list of existing
+     * <tt>InStreamDesc</tt>s in which an <tt>InStreamDesc</tt> for
+     * <tt>inStream</tt> is to be located
+     * @return an <tt>InStreamDesc</tt> from
+     * <tt>existingInStreamDescs</tt> which describes <tt>inStream</tt> if
+     * such an <tt>InStreamDesc</tt> exists; otherwise, <tt>null</tt>
      */
-    private static Format getFormat(DataSource dataSource)
+    private InStreamDesc getExistingInStreamDesc(
+            SourceStream inStream,
+            InStreamDesc[] existingInStreamDescs)
     {
-        FormatControl formatControl
-            = (FormatControl) dataSource.getControl(
-                    FormatControl.class.getName());
-
-        return (formatControl == null) ? null : formatControl.getFormat();
-    }
+        if (existingInStreamDescs == null)
+            return null;
 
-    /**
-     * Gets the <tt>Format</tt> in which a specific
-     * <tt>SourceStream</tt> provides data.
-     *
-     * @param stream
-     *            the <tt>SourceStream</tt> for which the
-     *            <tt>Format</tt> in which it provides data is to be
-     *            determined
-     * @return the <tt>Format</tt> in which the specified
-     *         <tt>SourceStream</tt> provides data if it was determined;
-     *         otherwise, <tt>null</tt>
-     */
-    private static Format getFormat(SourceStream stream)
-    {
-        if (stream instanceof PushBufferStream)
-            return ((PushBufferStream) stream).getFormat();
-        if (stream instanceof PullBufferStream)
-            return ((PullBufferStream) stream).getFormat();
+        for (InStreamDesc existingInStreamDesc
+                : existingInStreamDescs)
+        {
+            SourceStream existingInStream
+                = existingInStreamDesc.getInStream();
+
+            if (existingInStream == inStream)
+                return existingInStreamDesc;
+            if ((existingInStream instanceof BufferStreamAdapter<?>)
+                    && (((BufferStreamAdapter<?>) existingInStream).getStream()
+                            == inStream))
+                return existingInStreamDesc;
+            if ((existingInStream instanceof CachingPushBufferStream)
+                    && (((CachingPushBufferStream) existingInStream).getStream()
+                            == inStream))
+                return existingInStreamDesc;
+        }
         return null;
     }
 
@@ -638,114 +635,103 @@ FormatControl[] getFormatControls()
     }
 
     /**
-     * Gets the <tt>SourceStream</tt>s (in the form of <tt>InputStreamDesc</tt>)
+     * Gets the <tt>SourceStream</tt>s (in the form of <tt>InStreamDesc</tt>)
      * of a specific <tt>DataSource</tt> (provided in the form of
-     * <tt>InputDataSourceDesc</tt>) which produce data in a specific
+     * <tt>InDataSourceDesc</tt>) which produce data in a specific
      * <tt>AudioFormat</tt> (or a matching one).
      *
-     * @param inputDataSourceDesc the <tt>DataSource</tt> (in the form of
-     * <tt>InputDataSourceDesc</tt>) which is to be examined for
+     * @param inDataSourceDesc the <tt>DataSource</tt> (in the form of
+     * <tt>InDataSourceDesc</tt>) which is to be examined for
      * <tt>SourceStreams</tt> producing data in the specified
      * <tt>AudioFormat</tt>
-     * @param outputFormat the <tt>AudioFormat</tt> in which the collected
+     * @param outFormat the <tt>AudioFormat</tt> in which the collected
      * <tt>SourceStream</tt>s are to produce data
-     * @param existingInputStreams the <tt>InputStreamDesc</tt> instances which
+     * @param existingInStreams the <tt>InStreamDesc</tt> instances which
      * already exist and which are used to avoid creating multiple
-     * <tt>InputStreamDesc</tt>s for input <tt>SourceStream</tt>s which already
+     * <tt>InStreamDesc</tt>s for input <tt>SourceStream</tt>s which already
      * have ones
-     * @param inputStreams the <tt>List</tt> of <tt>InputStreamDesc</tt> in
+     * @param inStreams the <tt>List</tt> of <tt>InStreamDesc</tt> in
      * which the discovered <tt>SourceStream</tt>s are to be returned
      * @return <tt>true</tt> if <tt>SourceStream</tt>s produced by the specified
      * input <tt>DataSource</tt> and outputting data in the specified
      * <tt>AudioFormat</tt> were discovered and reported in
-     * <tt>inputStreams</tt>; otherwise, <tt>false</tt>
+     * <tt>inStreams</tt>; otherwise, <tt>false</tt>
      */
-    private boolean getInputStreamsFromInputDataSource(
-        InputDataSourceDesc inputDataSourceDesc,
-        AudioFormat outputFormat,
-        InputStreamDesc[] existingInputStreams,
-        List<InputStreamDesc> inputStreams)
+    private boolean getInStreamsFromInDataSource(
+            InDataSourceDesc inDataSourceDesc,
+            AudioFormat outFormat,
+            InStreamDesc[] existingInStreams,
+            List<InStreamDesc> inStreams)
     {
-        SourceStream[] inputDataSourceStreams
-            = inputDataSourceDesc.getStreams();
+        SourceStream[] inDataSourceStreams = inDataSourceDesc.getStreams();
 
-        if (inputDataSourceStreams != null)
+        if (inDataSourceStreams != null)
         {
             boolean added = false;
 
-            for (SourceStream inputStream : inputDataSourceStreams)
+            for (SourceStream inStream : inDataSourceStreams)
             {
-                Format inputFormat = getFormat(inputStream);
+                Format inFormat = getFormat(inStream);
 
-                if ((inputFormat != null)
-                        && matches(inputFormat, outputFormat))
+                if ((inFormat != null) && matches(inFormat, outFormat))
                 {
-                    InputStreamDesc inputStreamDesc
-                        = getExistingInputStreamDesc(
-                            inputStream,
-                            existingInputStreams);
-
-                    if (inputStreamDesc == null)
-                        inputStreamDesc
-                            = createInputStreamDesc(
-                                    inputStream,
-                                    inputDataSourceDesc);
-                    if (inputStreams.add(inputStreamDesc))
+                    InStreamDesc inStreamDesc
+                        = getExistingInStreamDesc(inStream, existingInStreams);
+
+                    if (inStreamDesc == null)
+                        inStreamDesc
+                            = createInStreamDesc(inStream, inDataSourceDesc);
+                    if (inStreams.add(inStreamDesc))
                         added = true;
                 }
             }
             return added;
         }
 
-        DataSource inputDataSource
-            = inputDataSourceDesc.getEffectiveInputDataSource();
+        DataSource inDataSource = inDataSourceDesc.getEffectiveInDataSource();
 
-        if (inputDataSource == null)
+        if (inDataSource == null)
             return false;
 
-        Format inputFormat = getFormat(inputDataSource);
+        Format inFormat = getFormat(inDataSource);
 
-        if ((inputFormat != null) && !matches(inputFormat, outputFormat))
+        if ((inFormat != null) && !matches(inFormat, outFormat))
         {
-            if (inputDataSource instanceof PushDataSource)
+            if (inDataSource instanceof PushDataSource)
             {
-                for (PushSourceStream inputStream
-                        : ((PushDataSource) inputDataSource).getStreams())
+                for (PushSourceStream inStream
+                        : ((PushDataSource) inDataSource).getStreams())
                 {
-                    InputStreamDesc inputStreamDesc
-                        = getExistingInputStreamDesc(
-                            inputStream,
-                            existingInputStreams);
-
-                    if (inputStreamDesc == null)
-                        inputStreamDesc
-                            = createInputStreamDesc(
+                    InStreamDesc inStreamDesc
+                        = getExistingInStreamDesc(inStream, existingInStreams);
+
+                    if (inStreamDesc == null)
+                        inStreamDesc
+                            = createInStreamDesc(
                                     new PushBufferStreamAdapter(
-                                            inputStream,
-                                            inputFormat),
-                                    inputDataSourceDesc);
-                    inputStreams.add(inputStreamDesc);
+                                            inStream,
+                                            inFormat),
+                                    inDataSourceDesc);
+                    inStreams.add(inStreamDesc);
                 }
                 return true;
             }
-            if (inputDataSource instanceof PullDataSource)
+            if (inDataSource instanceof PullDataSource)
             {
-                for (PullSourceStream inputStream
-                        : ((PullDataSource) inputDataSource).getStreams())
+                for (PullSourceStream inStream
+                        : ((PullDataSource) inDataSource).getStreams())
                 {
-                    InputStreamDesc inputStreamDesc
-                        = getExistingInputStreamDesc(
-                            inputStream,
-                            existingInputStreams);
-
-                    if (inputStreamDesc == null)
-                        inputStreamDesc
-                            = createInputStreamDesc(
+                    InStreamDesc inStreamDesc
+                        = getExistingInStreamDesc(inStream, existingInStreams);
+
+                    if (inStreamDesc == null)
+                        inStreamDesc
+                            = createInStreamDesc(
                                     new PullBufferStreamAdapter(
-                                            inputStream,
-                                            inputFormat),
-                                    inputDataSourceDesc);
-                    inputStreams.add(inputStreamDesc);
+                                            inStream,
+                                            inFormat),
+                                    inDataSourceDesc);
+                    inStreams.add(inStreamDesc);
                 }
                 return true;
             }
@@ -754,54 +740,54 @@ && matches(inputFormat, outputFormat))
     }
 
     /**
-     * Gets the <tt>SourceStream</tt>s (in the form of <tt>InputStreamDesc</tt>)
+     * Gets the <tt>SourceStream</tt>s (in the form of <tt>InStreamDesc</tt>)
      * of the <tt>DataSource</tt>s from which this <tt>AudioMixer</tt> reads
      * data which produce data in a specific <tt>AudioFormat</tt>. When an input
      * <tt>DataSource</tt> does not have such <tt>SourceStream</tt>s, an attempt
      * is made to transcode its tracks so that such <tt>SourceStream</tt>s can
      * be retrieved from it after transcoding.
      *
-     * @param outputFormat the <tt>AudioFormat</tt> in which the retrieved
+     * @param outFormat the <tt>AudioFormat</tt> in which the retrieved
      * <tt>SourceStream</tt>s are to produce data
-     * @param existingInputStreams the <tt>SourceStream</tt>s which are already
+     * @param existingInStreams the <tt>SourceStream</tt>s which are already
      * known to this <tt>AudioMixer</tt>
      * @return a new collection of <tt>SourceStream</tt>s (in the form of
-     * <tt>InputStreamDesc</tt>) retrieved from the input <tt>DataSource</tt>s
+     * <tt>InStreamDesc</tt>) retrieved from the input <tt>DataSource</tt>s
      * of this <tt>AudioMixer</tt> and producing data in the specified
      * <tt>AudioFormat</tt>
      * @throws IOException if anything wrong goes while retrieving the input
      * <tt>SourceStream</tt>s from the input <tt>DataSource</tt>s
      */
-    private Collection<InputStreamDesc> getInputStreamsFromInputDataSources(
-            AudioFormat outputFormat,
-            InputStreamDesc[] existingInputStreams)
+    private Collection<InStreamDesc> getInStreamsFromInDataSources(
+            AudioFormat outFormat,
+            InStreamDesc[] existingInStreams)
         throws IOException
     {
-        List<InputStreamDesc> inputStreams = new ArrayList<InputStreamDesc>();
+        List<InStreamDesc> inStreams = new ArrayList<InStreamDesc>();
 
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
+            for (InDataSourceDesc inDataSourceDesc : inDataSources)
             {
                 boolean got
-                    = getInputStreamsFromInputDataSource(
-                            inputDataSourceDesc,
-                            outputFormat,
-                            existingInputStreams,
-                            inputStreams);
+                    = getInStreamsFromInDataSource(
+                            inDataSourceDesc,
+                            outFormat,
+                            existingInStreams,
+                            inStreams);
 
                 if (!got
                         && createTranscodingDataSource(
-                                inputDataSourceDesc,
-                                outputFormat))
-                    getInputStreamsFromInputDataSource(
-                        inputDataSourceDesc,
-                        outputFormat,
-                        existingInputStreams,
-                        inputStreams);
+                                inDataSourceDesc,
+                                outFormat))
+                    getInStreamsFromInDataSource(
+                        inDataSourceDesc,
+                        outFormat,
+                        existingInStreams,
+                        inStreams);
             }
         }
-        return inputStreams;
+        return inStreams;
     }
 
     /**
@@ -815,9 +801,9 @@ && createTranscodingDataSource(
      * this <tt>AudioMixer</tt> and is thus meant for playback on the local peer
      * in a call
      */
-    public AudioMixingPushBufferDataSource getLocalOutputDataSource()
+    public AudioMixingPushBufferDataSource getLocalOutDataSource()
     {
-        return localOutputDataSource;
+        return localOutDataSource;
     }
 
     /**
@@ -831,24 +817,24 @@ public AudioMixingPushBufferDataSource getLocalOutputDataSource()
      *         produce data and which is to be the output <tt>Format</tt> of
      *         this <tt>AudioMixer</tt>
      */
-    private AudioFormat getOutputFormatFromInputDataSources()
+    private AudioFormat getOutFormatFromInDataSources()
     {
         String formatControlType = FormatControl.class.getName();
-        AudioFormat outputFormat = null;
+        AudioFormat outFormat = null;
 
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            for (InputDataSourceDesc inputDataSource : inputDataSources)
+            for (InDataSourceDesc inDataSource : inDataSources)
             {
-                DataSource effectiveInputDataSource
-                    = inputDataSource.getEffectiveInputDataSource();
+                DataSource effectiveInDataSource
+                    = inDataSource.getEffectiveInDataSource();
 
-                if (effectiveInputDataSource == null)
+                if (effectiveInDataSource == null)
                     continue;
 
                 FormatControl formatControl
                     = (FormatControl)
-                        effectiveInputDataSource.getControl(formatControlType);
+                        effectiveInDataSource.getControl(formatControlType);
 
                 if (formatControl != null)
                 {
@@ -869,7 +855,7 @@ private AudioFormat getOutputFormatFromInputDataSources()
                             if ((AudioFormat.LITTLE_ENDIAN == endian)
                                     || (Format.NOT_SPECIFIED == endian))
                             {
-                                outputFormat = format;
+                                outFormat = format;
                                 break;
                             }
                         }
@@ -878,17 +864,16 @@ private AudioFormat getOutputFormatFromInputDataSources()
             }
         }
 
-        if (outputFormat == null)
-            outputFormat = DEFAULT_OUTPUT_FORMAT;
+        if (outFormat == null)
+            outFormat = DEFAULT_OUTPUT_FORMAT;
 
         if (logger.isTraceEnabled())
         {
             logger.trace(
-                    "Determined outputFormat of AudioMixer"
-                        + " from inputDataSources to be "
-                        + outputFormat);
+                    "Determined outFormat of AudioMixer from inDataSources" +
+                        " to be " + outFormat);
         }
-        return outputFormat;
+        return outFormat;
     }
 
     /**
@@ -898,45 +883,74 @@ private AudioFormat getOutputFormatFromInputDataSources()
      * output <tt>AudioMixingPushBufferStream</tt>s for audio mixing.
      *
      * @return the <tt>AudioMixerPushBufferStream</tt> which reads data from
-     *         the input <tt>DataSource</tt>s of this
-     *         <tt>AudioMixer</tt> and pushes it to output
-     *         <tt>AudioMixingPushBufferStream</tt>s for audio mixing
+     * the input <tt>DataSource</tt>s of this <tt>AudioMixer</tt> and pushes it
+     * to output <tt>AudioMixingPushBufferStream</tt>s for audio mixing
      */
-    AudioMixerPushBufferStream getOutputStream()
+    AudioMixerPushBufferStream getOutStream()
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            AudioFormat outputFormat
-                = (outputStream == null)
-                    ? getOutputFormatFromInputDataSources()
-                    : outputStream.getFormat();
+            AudioFormat outFormat
+                = (outStream == null)
+                    ? getOutFormatFromInDataSources()
+                    : outStream.getFormat();
 
-            setOutputFormatToInputDataSources(outputFormat);
+            setOutFormatToInDataSources(outFormat);
 
-            Collection<InputStreamDesc> inputStreams;
+            Collection<InStreamDesc> inStreams;
 
             try
             {
-                inputStreams
-                    = getInputStreamsFromInputDataSources(
-                        outputFormat,
-                        (outputStream == null)
-                            ? null
-                            : outputStream.getInputStreams());
+                inStreams
+                    = getInStreamsFromInDataSources(
+                        outFormat,
+                        (outStream == null) ? null : outStream.getInStreams());
             }
             catch (IOException ioex)
             {
                 throw new UndeclaredThrowableException(ioex);
             }
 
-            if (outputStream == null)
-                outputStream
-                    = new AudioMixerPushBufferStream(this, outputFormat);
-            outputStream.setInputStreams(inputStreams);
-            return outputStream;
+            if (outStream == null)
+                outStream = new AudioMixerPushBufferStream(this, outFormat);
+            outStream.setInStreams(inStreams);
+            return outStream;
         }
     }
 
+    /**
+     * Searches this object's <tt>inDataSource</tt>s for one that matches
+     * <tt>inDataSource</tt>, and returns it's associated
+     * <tt>TranscodingDataSource</tt>. Currently this is only used when
+     * the <tt>MediaStream</tt> needs access to the codec chain used to
+     * playback one of it's <tt>ReceiveStream</tt>s.
+     *
+     * @param inDataSource the <tt>DataSource</tt> to search for.
+     * @return The <tt>TranscodingDataSource</tt> associated with
+     * <tt>inDataSource</tt>, if we can find one, <tt>null</tt> otherwise.
+     */
+    public TranscodingDataSource getTranscodingDataSource(
+            DataSource inDataSource)
+    {
+        for (InDataSourceDesc inDataSourceDesc : inDataSources)
+        {
+            DataSource ourDataSource = inDataSourceDesc.getInDataSource();
+
+            if (ourDataSource == inDataSource)
+                return inDataSourceDesc.getTranscodingDataSource();
+            else if (ourDataSource instanceof ReceiveStreamPushBufferDataSource)
+            {
+                // Sometimes the inDataSource has come to AudioMixer wrapped in
+                // a ReceiveStreamPushBufferDataSource. We consider it to match.
+                if (((ReceiveStreamPushBufferDataSource) ourDataSource)
+                            .getDataSource()
+                        == inDataSource)
+                    return inDataSourceDesc.getTranscodingDataSource();
+            }
+        }
+        return null;
+    }
+
     /**
      * Determines whether a specific <tt>Format</tt> matches a specific
      * <tt>Format</tt> in the sense of JMF <tt>Format</tt> matching.
@@ -946,16 +960,13 @@ AudioMixerPushBufferStream getOutputStream()
      * <tt>Format</tt>s to match is for both of them to have one and the
      * same encoding.
      *
-     * @param input
-     *            the <tt>Format</tt> for which it is required to determine
-     *            whether it matches a specific <tt>Format</tt>
-     * @param pattern
-     *            the <tt>Format</tt> against which the specified
-     *            <tt>input</tt> is to be matched
-     * @return <tt>true</tt> if the specified
-     *         <tt>input<tt> matches the specified <tt>pattern</tt> in
-     *         the sense of JMF <tt>Format</tt> matching; otherwise,
-     *         <tt>false</tt>
+     * @param input the <tt>Format</tt> for which it is required to determine
+     * whether it matches a specific <tt>Format</tt>
+     * @param pattern the <tt>Format</tt> against which the specified
+     * <tt>input</tt> is to be matched
+     * @return <tt>true</tt> if the specified <tt>input<tt> matches the
+     * specified <tt>pattern</tt> in the sense of JMF <tt>Format</tt> matching;
+     * otherwise, <tt>false</tt>
      */
     private boolean matches(Format input, AudioFormat pattern)
     {
@@ -997,25 +1008,25 @@ protected void read(
      * <tt>DataSource</tt>s of this <tt>AudioMixer</tt> from which it reads
      * audio to be mixed
      */
-    public void removeInputDataSources(DataSourceFilter dataSourceFilter)
+    public void removeInDataSources(DataSourceFilter dataSourceFilter)
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            Iterator<InputDataSourceDesc> inputDataSourceIter
-                = inputDataSources.iterator();
+            Iterator<InDataSourceDesc> inDataSourceIter
+                = inDataSources.iterator();
             boolean removed = false;
 
-            while (inputDataSourceIter.hasNext())
+            while (inDataSourceIter.hasNext())
             {
-                if (dataSourceFilter
-                        .accept(inputDataSourceIter.next().inputDataSource))
+                if (dataSourceFilter.accept(
+                        inDataSourceIter.next().inDataSource))
                 {
-                    inputDataSourceIter.remove();
+                    inDataSourceIter.remove();
                     removed = true;
                 }
             }
-            if (removed && (outputStream != null))
-                getOutputStream();
+            if (removed && (outStream != null))
+                getOutStream();
         }
     }
 
@@ -1025,49 +1036,43 @@ public void removeInputDataSources(DataSourceFilter dataSourceFilter)
      * <tt>AudioMixer</tt> in an attempt to not have to perform explicit
      * transcoding of the input <tt>SourceStream</tt>s.
      *
-     * @param outputFormat
-     *            the <tt>AudioFormat</tt> in which the input
-     *            <tt>DataSource</tt>s of this <tt>AudioMixer</tt> are
-     *            to be instructed to output
+     * @param outFormat the <tt>AudioFormat</tt> in which the input
+     * <tt>DataSource</tt>s of this <tt>AudioMixer</tt> are to be instructed to
+     * output
      */
-    private void setOutputFormatToInputDataSources(AudioFormat outputFormat)
+    private void setOutFormatToInDataSources(AudioFormat outFormat)
     {
         String formatControlType = FormatControl.class.getName();
 
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
-            for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
+            for (InDataSourceDesc inDataSourceDesc : inDataSources)
             {
                 FormatControl formatControl
                     = (FormatControl)
-                        inputDataSourceDesc.getControl(formatControlType);
+                        inDataSourceDesc.getControl(formatControlType);
 
                 if (formatControl != null)
                 {
-                    Format inputFormat = formatControl.getFormat();
+                    Format inFormat = formatControl.getFormat();
 
-                    if ((inputFormat == null)
-                            || !matches(inputFormat, outputFormat))
+                    if ((inFormat == null) || !matches(inFormat, outFormat))
                     {
                         Format setFormat
-                            = formatControl.setFormat(outputFormat);
+                            = formatControl.setFormat(outFormat);
 
                         if (setFormat == null)
-                            logger
-                                .error(
-                                    "Failed to set format of inputDataSource to "
-                                        + outputFormat);
-                        else if (setFormat != outputFormat)
-                            logger
-                                .warn(
-                                    "Failed to change format of inputDataSource from "
-                                        + setFormat
-                                        + " to "
-                                        + outputFormat);
+                            logger.error(
+                                    "Failed to set format of inDataSource to "
+                                        + outFormat);
+                        else if (setFormat != outFormat)
+                            logger.warn(
+                                    "Failed to change format of inDataSource"
+                                        + " from " + setFormat + " to "
+                                        + outFormat);
                         else if (logger.isTraceEnabled())
-                            logger
-                                .trace(
-                                    "Set format of inputDataSource to "
+                            logger.trace(
+                                    "Set format of inDataSource to "
                                         + setFormat);
                     }
                 }
@@ -1078,30 +1083,30 @@ else if (logger.isTraceEnabled())
     /**
      * Starts the input <tt>DataSource</tt>s of this <tt>AudioMixer</tt>.
      *
-     * @param outputStream the <tt>AudioMixerPushBufferStream</tt> which
-     * requests this <tt>AudioMixer</tt> to start. If <tt>outputStream</tt> is
+     * @param outStream the <tt>AudioMixerPushBufferStream</tt> which
+     * requests this <tt>AudioMixer</tt> to start. If <tt>outStream</tt> is
      * the current one and only <tt>AudioMixerPushBufferStream</tt> of this
      * <tt>AudioMixer</tt>, this <tt>AudioMixer</tt> starts if it hasn't started
      * yet. Otherwise, the request is ignored.
      * @throws IOException if any of the input <tt>DataSource</tt>s of this
      * <tt>AudioMixer</tt> throws such an exception while attempting to start it
      */
-    void start(AudioMixerPushBufferStream outputStream)
+    void start(AudioMixerPushBufferStream outStream)
         throws IOException
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
             /*
-             * AudioMixer has only one outputStream at a time and only its
-             * current outputStream knows when it has to start (and stop).
+             * AudioMixer has only one outStream at a time and only its
+             * current outStream knows when it has to start (and stop).
              */
-            if (this.outputStream != outputStream)
+            if (this.outStream != outStream)
                 return;
 
             if (started == 0)
             {
-                for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
-                    inputDataSourceDesc.start();
+                for (InDataSourceDesc inDataSourceDesc : inDataSources)
+                    inDataSourceDesc.start();
             }
 
             started++;
@@ -1111,24 +1116,24 @@ void start(AudioMixerPushBufferStream outputStream)
     /**
      * Stops the input <tt>DataSource</tt>s of this <tt>AudioMixer</tt>.
      *
-     * @param outputStream the <tt>AudioMixerPushBufferStream</tt> which
-     * requests this <tt>AudioMixer</tt> to stop. If <tt>outputStream</tt> is
+     * @param outStream the <tt>AudioMixerPushBufferStream</tt> which
+     * requests this <tt>AudioMixer</tt> to stop. If <tt>outStream</tt> is
      * the current one and only <tt>AudioMixerPushBufferStream</tt> of this
      * <tt>AudioMixer</tt>, this <tt>AudioMixer</tt> stops. Otherwise, the
      * request is ignored.
      * @throws IOException if any of the input <tt>DataSource</tt>s of this
      * <tt>AudioMixer</tt> throws such an exception while attempting to stop it
      */
-    void stop(AudioMixerPushBufferStream outputStream)
+    void stop(AudioMixerPushBufferStream outStream)
         throws IOException
     {
-        synchronized (inputDataSources)
+        synchronized (inDataSources)
         {
             /*
-             * AudioMixer has only one outputStream at a time and only its
-             * current outputStream known when it has to stop (and start).
+             * AudioMixer has only one outStream at a time and only its
+             * current outStream known when it has to stop (and start).
              */
-            if (this.outputStream != outputStream)
+            if (this.outStream != outStream)
                 return;
 
             if (started <= 0)
@@ -1138,42 +1143,9 @@ void stop(AudioMixerPushBufferStream outputStream)
 
             if (started == 0)
             {
-                for (InputDataSourceDesc inputDataSourceDesc : inputDataSources)
-                    inputDataSourceDesc.stop();
+                for (InDataSourceDesc inDataSourceDesc : inDataSources)
+                    inDataSourceDesc.stop();
             }
         }
     }
-
-    /**
-     * Searches this object's <tt>inputDataSource</tt>s for one that matches
-     * <tt>inputDataSource</tt>, and returns it's associated
-     * <tt>TranscodingDataSource</tt>. Currently this is only used when
-     * the <tt>MediaStream</tt> needs access to the codec chain used to
-     * playback one of it's <tt>ReceiveStream</tt>s.
-     *
-     * @param inputDataSource the <tt>DataSource</tt> to search for.
-     *
-     * @return The <tt>TranscodingDataSource</tt> associated with
-     * <tt>inputDataSource</tt>, if we can find one, <tt>null</tt> otherwise.
-     */
-    public TranscodingDataSource
-                getTranscodingDataSource(DataSource inputDataSource)
-    {
-        for(InputDataSourceDesc inputDataSourceDesc : inputDataSources)
-        {
-            DataSource ourDataSource = inputDataSourceDesc.getInputDataSource();
-            if(ourDataSource == inputDataSource)
-                return inputDataSourceDesc.getTranscodingDataSource();
-            else if(ourDataSource instanceof ReceiveStreamPushBufferDataSource)
-            {
-                //sometimes the inputDataSource has come to AudioMixer
-                //wrapped in a ReceiveStreamPushBufferDataSource. We consider
-                //it to match
-                if(((ReceiveStreamPushBufferDataSource) ourDataSource)
-                    .getDataSource() == inputDataSource)
-                    return inputDataSourceDesc.getTranscodingDataSource();
-            }
-        }
-        return null;
-    }
 }
diff --git a/src/org/jitsi/impl/neomedia/conference/AudioMixerPushBufferStream.java b/src/org/jitsi/impl/neomedia/conference/AudioMixerPushBufferStream.java
index ed1d5085..946b58b8 100644
--- a/src/org/jitsi/impl/neomedia/conference/AudioMixerPushBufferStream.java
+++ b/src/org/jitsi/impl/neomedia/conference/AudioMixerPushBufferStream.java
@@ -38,11 +38,133 @@ class AudioMixerPushBufferStream
     implements PushBufferStream
 {
     /**
-     * The <tt>Logger</tt> used by the <tt>AudioMixerPushBufferStream</tt> class
-     * and its instances for logging output.
+     * Describes a specific set of audio samples read from a specific set of
+     * input streams specified by their <tt>InStreamDesc</tt>s.
      */
-    private static final Logger logger
-        = Logger.getLogger(AudioMixerPushBufferStream.class);
+    private static class InSampleDesc
+    {
+        /**
+         * The <tt>Buffer</tt> into which media data is to be read from
+         * {@link #inStreams}.
+         */
+        private SoftReference<Buffer> buffer;
+
+        /**
+         * The <tt>AudioFormat</tt> of {@link #inSamples}.
+         */
+        private final AudioFormat format;
+
+        /**
+         * The set of audio samples read from {@link #inStreams}.
+         */
+        public final int[][] inSamples;
+
+        /**
+         * The set of input streams from which {@link #inSamples} were read.
+         */
+        public final InStreamDesc[] inStreams;
+
+        /**
+         * The time stamp of <tt>inSamples</tt> to be reported in the
+         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
+         * mixes are read from them.
+         */
+        private long timeStamp = Buffer.TIME_UNKNOWN;
+
+        /**
+         * Initializes a new <tt>InSampleDesc</tt> instance which is to
+         * describe a specific set of audio samples read from a specific set of
+         * input streams specified by their <tt>InStreamDesc</tt>s.
+         *
+         * @param inSamples the set of audio samples read from
+         * <tt>inStreams</tt>
+         * @param inStreams the set of input streams from which
+         * <tt>inSamples</tt> were read
+         * @param format the <tt>AudioFormat</tt> of <tt>inSamples</tt>
+         */
+        public InSampleDesc(
+                int[][] inSamples,
+                InStreamDesc[] inStreams,
+                AudioFormat format)
+        {
+            this.inSamples = inSamples;
+            this.inStreams = inStreams;
+            this.format = format;
+        }
+
+        /**
+         * Gets the <tt>Buffer</tt> into which media data is to be read from the
+         * input streams associated with this instance.
+         *
+         * @param create the indicator which determines whether the
+         * <tt>Buffer</tt> is to be created in case it does not exist
+         * @return the <tt>Buffer</tt> into which media data is to be read from
+         * the input streams associated with this instance
+         */
+        public Buffer getBuffer(boolean create)
+        {
+            Buffer buffer = (this.buffer == null) ? null : this.buffer.get();
+
+            if ((buffer == null) && create)
+            {
+                buffer = new Buffer();
+                setBuffer(buffer);
+            }
+            return buffer;
+        }
+
+        /**
+         * Gets the time stamp of <tt>inSamples</tt> to be reported in the
+         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
+         * mixes are read from them.
+         *
+         * @return the time stamp of <tt>inSamples</tt> to be reported in the
+         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
+         * mixes are read from them
+         */
+        public long getTimeStamp()
+        {
+            return timeStamp;
+        }
+
+        /**
+         * Sets the <tt>Buffer</tt> into which media data is to be read from the
+         * input streams associated with this instance.
+         *
+         * @param buffer the <tt>Buffer</tt> into which media data is to be read
+         * from the input streams associated with this instance
+         */
+        public void setBuffer(Buffer buffer)
+        {
+            this.buffer
+                = (buffer == null) ? null : new SoftReference<Buffer>(buffer);
+        }
+
+        /**
+         * Sets the time stamp of <tt>inSamples</tt> to be reported in the
+         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
+         * mixes are read from them.
+         *
+         * @param timeStamp the time stamp of <tt>inSamples</tt> to be
+         * reported in the <tt>Buffer</tt>s of the
+         * <tt>AudioMixingPushBufferStream</tt>s when mixes are read from them
+         */
+        public void setTimeStamp(long timeStamp)
+        {
+            if (this.timeStamp == Buffer.TIME_UNKNOWN)
+                this.timeStamp = timeStamp;
+            else
+            {
+                /*
+                 * Setting the timeStamp more than once does not make sense
+                 * because the inStreams will report different timeStamps so
+                 * only one should be picked up where the very reading from
+                 * inStreams takes place.
+                 */
+                throw new IllegalStateException("timeStamp");
+            }
+        }
+    }
 
     /**
      * The factor which scales a <tt>short</tt> value to an <tt>int</tt> value.
@@ -50,6 +172,13 @@ class AudioMixerPushBufferStream
     private static final float INT_TO_SHORT_RATIO
         = Integer.MAX_VALUE / (float) Short.MAX_VALUE;
 
+    /**
+     * The <tt>Logger</tt> used by the <tt>AudioMixerPushBufferStream</tt> class
+     * and its instances for logging output.
+     */
+    private static final Logger logger
+        = Logger.getLogger(AudioMixerPushBufferStream.class);
+
     /**
      * The factor which scales an <tt>int</tt> value to a <tt>short</tt> value.
      */
@@ -71,47 +200,36 @@ class AudioMixerPushBufferStream
     private final AudioMixer audioMixer;
 
     /**
-     * The <tt>SourceStream</tt>s (in the form of <tt>InputStreamDesc</tt> so
+     * The <tt>SourceStream</tt>s (in the form of <tt>InStreamDesc</tt> so
      * that this instance can track back the
      * <tt>AudioMixingPushBufferDataSource</tt> which outputs the mixed audio
      * stream and determine whether the associated <tt>SourceStream</tt> is to
      * be included into the mix) from which this instance reads its data.
      */
-    private InputStreamDesc[] inputStreams;
+    private InStreamDesc[] inStreams;
 
     /**
      * The <tt>Object</tt> which synchronizes the access to
-     * {@link #inputStreams}-related members.
-     */
-    private final Object inputStreamsSyncRoot = new Object();
-
-    /**
-     * The cache of <tt>int</tt> arrays managed by this instance for the
-     * purposes of reducing garbage collection.
+     * {@link #inStreams}-related members.
      */
-    private SoftReference<List<int[]>> intArrays;
-
-    /**
-     * The <tt>Object</tt> which synchronizes the access to {@link #intArrays}.
-     */
-    private final Object intArraysSyncRoot = new Object();
+    private final Object inStreamsSyncRoot = new Object();
 
     /**
      * The <tt>AudioFormat</tt> of the <tt>Buffer</tt> read during the last read
-     * from one of the {@link #inputStreams}. Only used for debugging purposes.
+     * from one of the {@link #inStreams}. Only used for debugging purposes.
      */
-    private AudioFormat lastReadInputFormat;
+    private AudioFormat lastReadInFormat;
 
     /**
      * The <tt>AudioFormat</tt> of the data this instance outputs.
      */
-    private final AudioFormat outputFormat;
+    private final AudioFormat outFormat;
 
     /**
      * The <tt>AudioMixingPushBufferStream</tt>s to which this instance pushes
      * data for audio mixing.
      */
-    private final List<AudioMixingPushBufferStream> outputStreams
+    private final List<AudioMixingPushBufferStream> outStreams
         = new ArrayList<AudioMixingPushBufferStream>();
 
     /**
@@ -144,15 +262,15 @@ public void transferData(PushBufferStream stream)
      *
      * @param audioMixer the <tt>AudioMixer</tt> which creates this instance and
      * for which it is to output data
-     * @param outputFormat the <tt>AudioFormat</tt> in which the new instance is
-     * to output data
+     * @param outFormat the <tt>AudioFormat</tt> in which the new instance is to
+     * output data
      */
     public AudioMixerPushBufferStream(
             AudioMixer audioMixer,
-            AudioFormat outputFormat)
+            AudioFormat outFormat)
     {
         this.audioMixer = audioMixer;
-        this.outputFormat = outputFormat;
+        this.outFormat = outFormat;
     }
 
     /**
@@ -160,24 +278,24 @@ public AudioMixerPushBufferStream(
      * such streams to which this instance is to push the data for audio mixing
      * it reads from its input <tt>SourceStream</tt>s.
      *
-     * @param outputStream the <tt>AudioMixingPushBufferStream</tt> to add to
+     * @param outStream the <tt>AudioMixingPushBufferStream</tt> to add to
      * the collection of such streams to which this instance is to push the data
      * for audio mixing it reads from its input <tt>SourceStream</tt>s
-     * @throws IOException if <tt>outputStream</tt> was the first
+     * @throws IOException if <tt>outStream</tt> was the first
      * <tt>AudioMixingPushBufferStream</tt> and the <tt>AudioMixer</tt> failed
      * to start
      */
-    void addOutputStream(AudioMixingPushBufferStream outputStream)
+    void addOutStream(AudioMixingPushBufferStream outStream)
         throws IOException
     {
-        if (outputStream == null)
-            throw new IllegalArgumentException("outputStream");
+        if (outStream == null)
+            throw new IllegalArgumentException("outStream");
 
-        synchronized (outputStreams)
+        synchronized (outStreams)
         {
-            if (!outputStreams.contains(outputStream)
-                    && outputStreams.add(outputStream)
-                    && (outputStreams.size() == 1))
+            if (!outStreams.contains(outStream)
+                    && outStreams.add(outStream)
+                    && (outStreams.size() == 1))
             {
                 boolean started = false;
 
@@ -189,64 +307,12 @@ void addOutputStream(AudioMixingPushBufferStream outputStream)
                 finally
                 {
                     if (!started)
-                        outputStreams.remove(outputStream);
+                        outStreams.remove(outStream);
                 }
             }
         }
     }
 
-    public int[] allocateIntArray(int minSize)
-    {
-        synchronized (intArraysSyncRoot)
-        {
-            List<int[]> intArrays
-                = (this.intArrays == null) ? null : this.intArrays.get();
-
-            if (intArrays != null)
-            {
-                Iterator<int[]> i = intArrays.iterator();
-
-                while (i.hasNext())
-                {
-                    int[] intArray = i.next();
-
-                    if (intArray.length >= minSize)
-                    {
-                        i.remove();
-                        return intArray;
-                    }
-                }
-            }
-        }
-
-        return new int[minSize];
-    }
-
-    public void deallocateIntArray(int[] intArray)
-    {
-        if (intArray == null)
-            return;
-
-        synchronized (intArraysSyncRoot)
-        {
-            List<int[]> intArrays;
-
-            if ((this.intArrays == null)
-                    || ((intArrays = this.intArrays.get()) == null))
-            {
-                intArrays = new LinkedList<int[]>();
-                this.intArrays = new SoftReference<List<int[]>>(intArrays);
-            }
-
-            if (intArrays.size() != 0)
-                for (int[] element : intArrays)
-                    if (element == intArray)
-                        return;
-
-            intArrays.add(intArray);
-        }
-    }
-
     /**
      * Implements {@link SourceStream#endOfStream()}. Delegates to the input
      * <tt>SourceStreams</tt> of this instance.
@@ -256,11 +322,11 @@ public void deallocateIntArray(int[] intArray)
      */
     public boolean endOfStream()
     {
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            if (inputStreams != null)
-                for (InputStreamDesc inputStreamDesc : inputStreams)
-                    if (!inputStreamDesc.getInputStream().endOfStream())
+            if (inStreams != null)
+                for (InStreamDesc inStreamDesc : inStreams)
+                    if (!inStreamDesc.getInStream().endOfStream())
                         return false;
         }
         return true;
@@ -268,34 +334,34 @@ public boolean endOfStream()
 
     /**
      * Attempts to equalize the length in milliseconds of the buffering
-     * performed by the <tt>inputStreams</tt> in order to always read and mix
+     * performed by the <tt>inStreams</tt> in order to always read and mix
      * one and the same length in milliseconds.
      */
-    void equalizeInputStreamBufferLength()
+    void equalizeInStreamBufferLength()
     {
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            if ((inputStreams == null) || (inputStreams.length < 1))
+            if ((inStreams == null) || (inStreams.length < 1))
                 return;
 
             /*
-             * The first inputStream is expected to be from the CaptureDevice
+             * The first inStream is expected to be from the CaptureDevice
              * and no custom BufferControl is provided for it so the
              * bufferLength is whatever it says.
              */
-            BufferControl bufferControl = getBufferControl(inputStreams[0]);
+            BufferControl bufferControl = getBufferControl(inStreams[0]);
             long bufferLength
                 = (bufferControl == null)
                     ? CachingPushBufferStream.DEFAULT_BUFFER_LENGTH
                     : bufferControl.getBufferLength();
 
-            for (int i = 1; i < inputStreams.length; i++)
+            for (int i = 1; i < inStreams.length; i++)
             {
-                BufferControl inputStreamBufferControl
-                    = getBufferControl(inputStreams[i]);
+                BufferControl inStreamBufferControl
+                    = getBufferControl(inStreams[i]);
 
-                if (inputStreamBufferControl != null)
-                    inputStreamBufferControl.setBufferLength(bufferLength);
+                if (inStreamBufferControl != null)
+                    inStreamBufferControl.setBufferLength(bufferLength);
             }
         }
     }
@@ -306,7 +372,7 @@ void equalizeInputStreamBufferLength()
      * <tt>DataSource</tt>, its transcoding <tt>DataSource</tt> if any or the
      * very input stream.
      *
-     * @param inputStreamDesc an <tt>InputStreamDesc</tt> which describes the
+     * @param inStreamDesc an <tt>InStreamDesc</tt> which describes the
      * input stream and its originating <tt>DataSource</tt>s from which the
      * <tt>BufferControl</tt> is to be retrieved
      * @return the <tt>BufferControl</tt> of the specified input stream found in
@@ -314,21 +380,21 @@ void equalizeInputStreamBufferLength()
      * or the very input stream if such a control exists; otherwise,
      * <tt>null</tt>
      */
-    private BufferControl getBufferControl(InputStreamDesc inputStreamDesc)
+    private BufferControl getBufferControl(InStreamDesc inStreamDesc)
     {
-        InputDataSourceDesc inputDataSourceDesc
-            = inputStreamDesc.inputDataSourceDesc;
+        InDataSourceDesc inDataSourceDesc
+            = inStreamDesc.inDataSourceDesc;
 
-        // Try the DataSource which directly provides the specified inputStream.
-        DataSource effectiveInputDataSource
-            = inputDataSourceDesc.getEffectiveInputDataSource();
+        // Try the DataSource which directly provides the specified inStream.
+        DataSource effectiveInDataSource
+            = inDataSourceDesc.getEffectiveInDataSource();
         String bufferControlType = BufferControl.class.getName();
 
-        if (effectiveInputDataSource != null)
+        if (effectiveInDataSource != null)
         {
             BufferControl bufferControl
                 = (BufferControl)
-                    effectiveInputDataSource.getControl(bufferControlType);
+                    effectiveInDataSource.getControl(bufferControlType);
 
             if (bufferControl != null)
                 return bufferControl;
@@ -336,25 +402,25 @@ private BufferControl getBufferControl(InputStreamDesc inputStreamDesc)
 
         /*
          * If transcoding is taking place and the transcodingDataSource does not
-         * have a BufferControl, try the inputDataSource which is being
+         * have a BufferControl, try the inDataSource which is being
          * transcoded.
          */
-        DataSource inputDataSource = inputDataSourceDesc.inputDataSource;
+        DataSource inDataSource = inDataSourceDesc.inDataSource;
 
-        if ((inputDataSource != null)
-                && (inputDataSource != effectiveInputDataSource))
+        if ((inDataSource != null)
+                && (inDataSource != effectiveInDataSource))
         {
             BufferControl bufferControl
-                = (BufferControl) inputDataSource.getControl(bufferControlType);
+                = (BufferControl) inDataSource.getControl(bufferControlType);
 
             if (bufferControl != null)
                 return bufferControl;
         }
 
-        // If everything else has failed, try the very inputStream.
+        // If everything else has failed, try the very inStream.
         return
             (BufferControl)
-                inputStreamDesc.getInputStream().getControl(bufferControlType);
+                inStreamDesc.getInStream().getControl(bufferControlType);
     }
 
     /**
@@ -382,18 +448,18 @@ public long getContentLength()
     {
         long contentLength = 0;
 
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            if (inputStreams != null)
-                for (InputStreamDesc inputStreamDesc : inputStreams)
+            if (inStreams != null)
+                for (InStreamDesc inStreamDesc : inStreams)
                 {
-                    long inputContentLength
-                        = inputStreamDesc.getInputStream().getContentLength();
+                    long inContentLength
+                        = inStreamDesc.getInStream().getContentLength();
 
-                    if (LENGTH_UNKNOWN == inputContentLength)
+                    if (LENGTH_UNKNOWN == inContentLength)
                         return LENGTH_UNKNOWN;
-                    if (contentLength < inputContentLength)
-                        contentLength = inputContentLength;
+                    if (contentLength < inContentLength)
+                        contentLength = inContentLength;
                 }
         }
         return contentLength;
@@ -409,21 +475,21 @@ public long getContentLength()
      */
     public AudioFormat getFormat()
     {
-        return outputFormat;
+        return outFormat;
     }
 
     /**
      * Gets the <tt>SourceStream</tt>s (in the form of
-     * <tt>InputStreamDesc</tt>s) from which this instance reads audio samples.
+     * <tt>InStreamDesc</tt>s) from which this instance reads audio samples.
      *
-     * @return an array of <tt>InputStreamDesc</tt>s which describe the input
+     * @return an array of <tt>InStreamDesc</tt>s which describe the input
      * <tt>SourceStream</tt>s from which this instance reads audio samples
      */
-    InputStreamDesc[] getInputStreams()
+    InStreamDesc[] getInStreams()
     {
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            return (inputStreams == null) ? null : inputStreams.clone();
+            return (inStreams == null) ? null : inStreams.clone();
         }
     }
 
@@ -442,54 +508,57 @@ InputStreamDesc[] getInputStreams()
     public void read(Buffer buffer)
         throws IOException
     {
-        InputSampleDesc inputSampleDesc;
-        int inputStreamCount;
+        InSampleDesc inSampleDesc;
+        int inStreamCount;
+        AudioFormat format = getFormat();
 
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            InputStreamDesc[] thisInputStreams = this.inputStreams;
+            InStreamDesc[] inStreams = this.inStreams;
 
-            if ((thisInputStreams == null) || (thisInputStreams.length == 0))
+            if ((inStreams == null) || (inStreams.length == 0))
                 return;
             else
             {
-                inputSampleDesc = (InputSampleDesc) buffer.getData();
-                inputStreamCount = thisInputStreams.length;
-                if (inputSampleDesc != null)
+                inSampleDesc = (InSampleDesc) buffer.getData();
+                // format
+                if ((inSampleDesc != null) && inSampleDesc.format != format)
+                    inSampleDesc = null;
+                // inStreams
+                inStreamCount = inStreams.length;
+                if (inSampleDesc != null)
                 {
-                    InputStreamDesc[] inputSampleDescInputStreams
-                        = inputSampleDesc.inputStreams;
+                    InStreamDesc[] inSampleDescInStreams
+                        = inSampleDesc.inStreams;
 
-                    if (inputSampleDescInputStreams.length == inputStreamCount)
+                    if (inSampleDescInStreams.length == inStreamCount)
                     {
-                        for (int i = 0; i < inputStreamCount; i++)
-                            if (inputSampleDescInputStreams[i]
-                                    != thisInputStreams[i])
+                        for (int i = 0; i < inStreamCount; i++)
+                            if (inSampleDescInStreams[i] != inStreams[i])
                             {
-                                inputSampleDesc = null;
+                                inSampleDesc = null;
                                 break;
                             }
                     }
                     else
-                        inputSampleDesc = null;
+                        inSampleDesc = null;
                 }
-                if (inputSampleDesc == null)
+                if (inSampleDesc == null)
                 {
-                    inputSampleDesc
-                        = new InputSampleDesc(
-                                new int[inputStreamCount][],
-                                thisInputStreams.clone());
+                    inSampleDesc
+                        = new InSampleDesc(
+                                new int[inStreamCount][],
+                                inStreams.clone(),
+                                format);
                 }
             }
         }
 
-        AudioFormat outputFormat = getFormat();
-        int maxInputSampleCount;
+        int maxInSampleCount;
 
         try
         {
-            maxInputSampleCount
-                = readInputPushBufferStreams(outputFormat, inputSampleDesc);
+            maxInSampleCount = readInPushBufferStreams(format, inSampleDesc);
         }
         catch (UnsupportedFormatException ufex)
         {
@@ -499,22 +568,22 @@ public void read(Buffer buffer)
             throw ioex;
         }
 
-        maxInputSampleCount
+        maxInSampleCount
             = Math.max(
-                    maxInputSampleCount,
-                    readInputPullBufferStreams(
-                        outputFormat,
-                        maxInputSampleCount,
-                        inputSampleDesc));
+                    maxInSampleCount,
+                    readInPullBufferStreams(
+                            format,
+                            maxInSampleCount,
+                            inSampleDesc));
 
-        buffer.setData(inputSampleDesc);
-        buffer.setLength(maxInputSampleCount);
+        buffer.setData(inSampleDesc);
+        buffer.setLength(maxInSampleCount);
 
         /*
          * Convey the timeStamp so that it can be reported by the Buffers of
          * the AudioMixingPushBufferStreams when mixes are read from them.
          */
-        long timeStamp = inputSampleDesc.getTimeStamp();
+        long timeStamp = inSampleDesc.getTimeStamp();
 
         if (timeStamp != Buffer.TIME_UNKNOWN)
             buffer.setTimeStamp(timeStamp);
@@ -527,13 +596,13 @@ public void read(Buffer buffer)
      * the <tt>PullBufferStream</tt>s but the very <tt>PullBufferStream</tt> may
      * not honor the request.
      *
-     * @param outputFormat the <tt>AudioFormat</tt> in which the audio samples
+     * @param outFormat the <tt>AudioFormat</tt> in which the audio samples
      * read from the <tt>PullBufferStream</tt>s are to be converted before being
      * returned
-     * @param outputSampleCount the maximum number of audio samples to be read
+     * @param outSampleCount the maximum number of audio samples to be read
      * from each of the <tt>PullBufferStream</tt>s but the very
      * <tt>PullBufferStream</tt>s may not honor the request
-     * @param inputSampleDesc an <tt>InputStreamDesc</tt> which specifies the
+     * @param inSampleDesc an <tt>InStreamDesc</tt> which specifies the
      * input streams to be read and the collection of audio samples in which the
      * read audio samples are to be returned
      * @return the maximum number of audio samples actually read from the input
@@ -541,23 +610,22 @@ public void read(Buffer buffer)
      * @throws IOException if anything goes wrong while reading the specified
      * input streams
      */
-    private int readInputPullBufferStreams(
-            AudioFormat outputFormat,
-            int outputSampleCount,
-            InputSampleDesc inputSampleDesc)
+    private int readInPullBufferStreams(
+            AudioFormat outFormat,
+            int outSampleCount,
+            InSampleDesc inSampleDesc)
         throws IOException
     {
-        InputStreamDesc[] inputStreams = inputSampleDesc.inputStreams;
-        int maxInputSampleCount = 0;
-
-        for (InputStreamDesc inputStream : inputStreams)
-            if (inputStream.getInputStream() instanceof PullBufferStream)
-                throw
-                    new UnsupportedOperationException(
-                            AudioMixerPushBufferStream.class.getSimpleName()
-                                + ".readInputPullBufferStreams"
-                                + "(AudioFormat,int,InputSampleDesc)");
-        return maxInputSampleCount;
+        InStreamDesc[] inStreams = inSampleDesc.inStreams;
+        int maxInSampleCount = 0;
+
+        for (InStreamDesc inStream : inStreams)
+            if (inStream.getInStream() instanceof PullBufferStream)
+                throw new UnsupportedOperationException(
+                        AudioMixerPushBufferStream.class.getSimpleName()
+                            + ".readInPullBufferStreams"
+                            + "(AudioFormat,int,InSampleDesc)");
+        return maxInSampleCount;
     }
 
     /**
@@ -567,174 +635,173 @@ private int readInputPullBufferStreams(
      * <tt>PushBufferStream</tt> but the very <tt>PushBufferStream</tt> may not
      * honor the request.
      *
-     * @param inputStreamDesc an <tt>InputStreamDesc</tt> which specifies the
+     * @param inStreamDesc an <tt>InStreamDesc</tt> which specifies the
      * input <tt>PushBufferStream</tt> to read from
-     * @param outputFormat the <tt>AudioFormat</tt> to which the samples read
-     * from <tt>inputStream</tt> are to be converted before being returned
+     * @param outFormat the <tt>AudioFormat</tt> to which the samples read
+     * from <tt>inStream</tt> are to be converted before being returned
      * @param sampleCount the maximum number of samples which the read operation
-     * should attempt to read from <tt>inputStream</tt> but the very
-     * <tt>inputStream</tt> may not honor the request
-     * @param outputBuffer the <tt>Buffer</tt> into which the array of
-     * <tt>int</tt> audio samples read from the specified <tt>inputStream</tt>
+     * should attempt to read from <tt>inStream</tt> but the very
+     * <tt>inStream</tt> may not honor the request
+     * @param outBuffer the <tt>Buffer</tt> into which the array of
+     * <tt>int</tt> audio samples read from the specified <tt>inStream</tt>
      * is to be written
      * @throws IOException if anything wrong happens while reading
-     * <tt>inputStream</tt>
+     * <tt>inStream</tt>
      * @throws UnsupportedFormatException if converting the samples read from
-     * <tt>inputStream</tt> to <tt>outputFormat</tt> fails
+     * <tt>inStream</tt> to <tt>outFormat</tt> fails
      */
-    private void readInputPushBufferStream(
-            InputStreamDesc inputStreamDesc,
-            AudioFormat outputFormat,
+    private void readInPushBufferStream(
+            InStreamDesc inStreamDesc,
+            AudioFormat outFormat,
             int sampleCount,
-            Buffer outputBuffer)
+            Buffer outBuffer)
         throws IOException,
                UnsupportedFormatException
     {
-        PushBufferStream inputStream
-            = (PushBufferStream) inputStreamDesc.getInputStream();
-        AudioFormat inputStreamFormat
-            = (AudioFormat) inputStream.getFormat();
-        Buffer inputBuffer = inputStreamDesc.getBuffer(true);
+        PushBufferStream inStream
+            = (PushBufferStream) inStreamDesc.getInStream();
+        AudioFormat inStreamFormat = (AudioFormat) inStream.getFormat();
+        Buffer inBuffer = inStreamDesc.getBuffer(true);
 
         if (sampleCount != 0)
         {
-            Class<?> inputDataType = inputStreamFormat.getDataType();
-
-            if (Format.byteArray.equals(inputDataType))
+            if (Format.byteArray.equals(inStreamFormat.getDataType()))
             {
-                Object data = inputBuffer.getData();
+                Object data = inBuffer.getData();
                 int length
-                    = sampleCount
-                        * (inputStreamFormat.getSampleSizeInBits() / 8);
+                    = sampleCount * (inStreamFormat.getSampleSizeInBits() / 8);
 
                 if (!(data instanceof byte[])
                         || (((byte[]) data).length != length))
-                    inputBuffer.setData(new byte[length]);
-                inputBuffer.setLength(0);
-                inputBuffer.setOffset(0);
+                    inBuffer.setData(new byte[length]);
+                inBuffer.setLength(0);
+                inBuffer.setOffset(0);
             }
             else
             {
                 throw new UnsupportedFormatException(
                         "!Format.getDataType().equals(byte[].class)",
-                        inputStreamFormat);
+                        inStreamFormat);
             }
         }
 
         audioMixer.read(
-                inputStream,
-                inputBuffer,
-                inputStreamDesc.inputDataSourceDesc.inputDataSource);
+                inStream,
+                inBuffer,
+                inStreamDesc.inDataSourceDesc.inDataSource);
 
         /*
-         * If the media is to be discarded, don't even bother with the
-         * checks and the conversion.
+         * If the media is to be discarded, don't even bother with the checks
+         * and the conversion.
          */
-        if (inputBuffer.isDiscard())
+        if (inBuffer.isDiscard())
         {
-            outputBuffer.setDiscard(true);
+            outBuffer.setDiscard(true);
             return;
         }
 
-        int inputLength = inputBuffer.getLength();
+        int inLength = inBuffer.getLength();
 
-        if (inputLength <= 0)
+        if (inLength <= 0)
         {
-            outputBuffer.setDiscard(true);
+            outBuffer.setDiscard(true);
             return;
         }
 
-        AudioFormat inputFormat = (AudioFormat) inputBuffer.getFormat();
+        AudioFormat inFormat = (AudioFormat) inBuffer.getFormat();
 
-        if (inputFormat == null)
-            inputFormat = inputStreamFormat;
+        if (inFormat == null)
+            inFormat = inStreamFormat;
 
-        if (logger.isTraceEnabled()
-                && (lastReadInputFormat != null)
-                && !lastReadInputFormat.matches(inputFormat))
+        if (logger.isTraceEnabled())
         {
-            lastReadInputFormat = inputFormat;
-            logger.trace(
-                    "Read inputSamples in different format "
-                        + lastReadInputFormat);
+            if (lastReadInFormat == null)
+                lastReadInFormat = inFormat;
+            else if (!lastReadInFormat.matches(inFormat))
+            {
+                lastReadInFormat = inFormat;
+                logger.trace(
+                        "Read inSamples in different format "
+                            + lastReadInFormat);
+            }
         }
 
-        int inputFormatSigned = inputFormat.getSigned();
+        int inFormatSigned = inFormat.getSigned();
 
-        if ((inputFormatSigned != AudioFormat.SIGNED)
-                && (inputFormatSigned != Format.NOT_SPECIFIED))
+        if ((inFormatSigned != AudioFormat.SIGNED)
+                && (inFormatSigned != Format.NOT_SPECIFIED))
         {
             throw new UnsupportedFormatException(
                     "AudioFormat.getSigned()",
-                    inputFormat);
+                    inFormat);
         }
 
-        int inputChannels = inputFormat.getChannels();
-        int outputChannels = outputFormat.getChannels();
+        int inChannels = inFormat.getChannels();
+        int outChannels = outFormat.getChannels();
 
-        if ((inputChannels != outputChannels)
-                && (inputChannels != Format.NOT_SPECIFIED)
-                && (outputChannels != Format.NOT_SPECIFIED))
+        if ((inChannels != outChannels)
+                && (inChannels != Format.NOT_SPECIFIED)
+                && (outChannels != Format.NOT_SPECIFIED))
         {
             logger.error(
-                    "Read inputFormat with channels "
-                        + inputChannels
-                        + " while expected outputFormat channels is "
-                        + outputChannels);
+                    "Read inFormat with channels " + inChannels
+                        + " while expected outFormat channels is "
+                        + outChannels);
             throw new UnsupportedFormatException(
                     "AudioFormat.getChannels()",
-                    inputFormat);
+                    inFormat);
         }
 
         // Warn about different sampleRates.
-        double inputSampleRate = inputFormat.getSampleRate();
-        double outputSampleRate = outputFormat.getSampleRate();
+        double inSampleRate = inFormat.getSampleRate();
+        double outSampleRate = outFormat.getSampleRate();
 
-        if (inputSampleRate != outputSampleRate)
+        if (inSampleRate != outSampleRate)
         {
             logger.warn(
-                    "Read inputFormat with sampleRate "
-                        + inputSampleRate
-                        + " while expected outputFormat sampleRate is "
-                        + outputSampleRate);
+                    "Read inFormat with sampleRate " + inSampleRate
+                        + " while expected outFormat sampleRate is "
+                        + outSampleRate);
         }
 
-        Object inputData = inputBuffer.getData();
+        Object inData = inBuffer.getData();
 
-        if (inputData == null)
+        if (inData == null)
         {
-            outputBuffer.setDiscard(true);
+            outBuffer.setDiscard(true);
         }
-        else if (inputData instanceof byte[])
+        else if (inData instanceof byte[])
         {
-            int inputSampleSizeInBits = inputFormat.getSampleSizeInBits();
-            int outputSampleSizeInBits = outputFormat.getSampleSizeInBits();
+            int inSampleSizeInBits = inFormat.getSampleSizeInBits();
+            int outSampleSizeInBits = outFormat.getSampleSizeInBits();
 
             if (logger.isTraceEnabled()
-                    && (inputSampleSizeInBits != outputSampleSizeInBits))
+                    && (inSampleSizeInBits != outSampleSizeInBits))
             {
                 logger.trace(
-                        "Read inputFormat with sampleSizeInBits "
-                            + inputSampleSizeInBits
+                        "Read inFormat with sampleSizeInBits "
+                            + inSampleSizeInBits
                             + ". Will convert to sampleSizeInBits "
-                            + outputSampleSizeInBits);
+                            + outSampleSizeInBits);
             }
 
-            byte[] inputSamples = (byte[]) inputData;
-            int outputLength;
-            int[] outputSamples;
+            byte[] inSamples = (byte[]) inData;
+            int outLength;
+            int[] outSamples;
 
-            switch (inputSampleSizeInBits)
+            switch (inSampleSizeInBits)
             {
             case 16:
-                outputLength = inputLength / 2;
-                outputSamples
-                    = validateIntArraySize(outputBuffer, outputLength);
-                for (int i = 0; i < outputLength; i++)
+                outLength = inLength / 2;
+                outSamples
+                    = audioMixer.intArrayCache.validateIntArraySize(
+                            outBuffer,
+                            outLength);
+                for (int i = 0; i < outLength; i++)
                 {
-                    int sample = ArrayIOUtils.readInt16(inputSamples, i * 2);
+                    int sample = ArrayIOUtils.readInt16(inSamples, i * 2);
 
-                    switch (outputSampleSizeInBits)
+                    switch (outSampleSizeInBits)
                     {
                     case 16:
                         break;
@@ -746,21 +813,23 @@ else if (inputData instanceof byte[])
                     default:
                         throw new UnsupportedFormatException(
                                 "AudioFormat.getSampleSizeInBits()",
-                                outputFormat);
+                                outFormat);
                     }
 
-                    outputSamples[i] = sample;
+                    outSamples[i] = sample;
                 }
                 break;
             case 32:
-                outputLength = inputSamples.length / 4;
-                outputSamples
-                    = validateIntArraySize(outputBuffer, outputLength);
-                for (int i = 0; i < outputLength; i++)
+                outLength = inSamples.length / 4;
+                outSamples
+                    = audioMixer.intArrayCache.validateIntArraySize(
+                            outBuffer,
+                            outLength);
+                for (int i = 0; i < outLength; i++)
                 {
-                    int sample = readInt(inputSamples, i * 4);
+                    int sample = ArrayIOUtils.readInt(inSamples, i * 4);
 
-                    switch (outputSampleSizeInBits)
+                    switch (outSampleSizeInBits)
                     {
                     case 16:
                         sample = Math.round(sample * SHORT_TO_INT_RATIO);
@@ -772,10 +841,10 @@ else if (inputData instanceof byte[])
                     default:
                         throw new UnsupportedFormatException(
                                 "AudioFormat.getSampleSizeInBits()",
-                                outputFormat);
+                                outFormat);
                     }
 
-                    outputSamples[i] = sample;
+                    outSamples[i] = sample;
                 }
                 break;
             case 8:
@@ -783,20 +852,20 @@ else if (inputData instanceof byte[])
             default:
                 throw new UnsupportedFormatException(
                         "AudioFormat.getSampleSizeInBits()",
-                        inputFormat);
+                        inFormat);
             }
 
-            outputBuffer.setFlags(inputBuffer.getFlags());
-            outputBuffer.setFormat(outputFormat);
-            outputBuffer.setLength(outputLength);
-            outputBuffer.setOffset(0);
-            outputBuffer.setTimeStamp(inputBuffer.getTimeStamp());
+            outBuffer.setFlags(inBuffer.getFlags());
+            outBuffer.setFormat(outFormat);
+            outBuffer.setLength(outLength);
+            outBuffer.setOffset(0);
+            outBuffer.setTimeStamp(inBuffer.getTimeStamp());
         }
         else
         {
             throw new UnsupportedFormatException(
-                    "Format.getDataType().equals(" + inputData.getClass() + ")",
-                    inputFormat);
+                    "Format.getDataType().equals(" + inData.getClass() + ")",
+                    inFormat);
         }
     }
 
@@ -804,10 +873,10 @@ else if (inputData instanceof byte[])
      * Reads audio samples from the input <tt>PushBufferStream</tt>s of this
      * instance and converts them to a specific output <tt>AudioFormat</tt>.
      *
-     * @param outputFormat the <tt>AudioFormat</tt> in which the audio samples
+     * @param outFormat the <tt>AudioFormat</tt> in which the audio samples
      * read from the <tt>PushBufferStream</tt>s are to be converted before being
      * returned
-     * @param inputSampleDesc an <tt>InputSampleDesc</tt> which specifies the
+     * @param inSampleDesc an <tt>InSampleDesc</tt> which specifies the
      * input streams to be read and  the collection of audio samples in which
      * the read audio samples are to be returned
      * @return the maximum number of audio samples actually read from the input
@@ -815,30 +884,30 @@ else if (inputData instanceof byte[])
      * @throws IOException if anything wrong happens while reading the specified
      * input streams
      * @throws UnsupportedFormatException if any of the input streams provides
-     * media in a format different than <tt>outputFormat</tt>
+     * media in a format different than <tt>outFormat</tt>
      */
-    private int readInputPushBufferStreams(
-            AudioFormat outputFormat,
-            InputSampleDesc inputSampleDesc)
+    private int readInPushBufferStreams(
+            AudioFormat outFormat,
+            InSampleDesc inSampleDesc)
         throws IOException,
                UnsupportedFormatException
     {
-        InputStreamDesc[] inputStreams = inputSampleDesc.inputStreams;
-        Buffer buffer = inputSampleDesc.getBuffer(true);
-        int maxInputSampleCount = 0;
-        int[][] inputSamples = inputSampleDesc.inputSamples;
+        InStreamDesc[] inStreams = inSampleDesc.inStreams;
+        Buffer buffer = inSampleDesc.getBuffer(true);
+        int maxInSampleCount = 0;
+        int[][] inSamples = inSampleDesc.inSamples;
 
-        for (int i = 0; i < inputStreams.length; i++)
+        for (int i = 0; i < inStreams.length; i++)
         {
-            InputStreamDesc inputStreamDesc = inputStreams[i];
-            SourceStream inputStream = inputStreamDesc.getInputStream();
+            InStreamDesc inStreamDesc = inStreams[i];
+            SourceStream inStream = inStreamDesc.getInStream();
 
-            if (inputStream instanceof PushBufferStream)
+            if (inStream instanceof PushBufferStream)
             {
                 buffer.setDiscard(false);
                 buffer.setLength(0);
-                readInputPushBufferStream(
-                        inputStreamDesc, outputFormat, maxInputSampleCount,
+                readInPushBufferStream(
+                        inStreamDesc, outFormat, maxInSampleCount,
                         buffer);
 
                 int sampleCount;
@@ -868,18 +937,16 @@ private int readInputPushBufferStreams(
                     if ((TRACE_NON_CONTRIBUTING_READ_COUNT > 0)
                             && logger.isTraceEnabled())
                     {
-                        inputStreamDesc.nonContributingReadCount++;
-                        if (inputStreamDesc.nonContributingReadCount
+                        inStreamDesc.nonContributingReadCount++;
+                        if (inStreamDesc.nonContributingReadCount
                                 >= TRACE_NON_CONTRIBUTING_READ_COUNT)
                         {
                             logger.trace(
                                     "Failed to read actual inputSamples more than "
-                                        + inputStreamDesc
-                                                .nonContributingReadCount
+                                        + inStreamDesc.nonContributingReadCount
                                         + " times from inputStream with hash code "
-                                        + inputStreamDesc
-                                                .getInputStream().hashCode());
-                            inputStreamDesc.nonContributingReadCount = 0;
+                                        + inStreamDesc.getInStream().hashCode());
+                            inStreamDesc.nonContributingReadCount = 0;
                         }
                     }
                 }
@@ -898,10 +965,10 @@ private int readInputPushBufferStreams(
                     if (samples.length > sampleCount)
                         Arrays.fill(samples, sampleCount, samples.length, 0);
 
-                    inputSamples[i] = samples;
+                    inSamples[i] = samples;
 
-                    if (maxInputSampleCount < samples.length)
-                        maxInputSampleCount = samples.length;
+                    if (maxInSampleCount < samples.length)
+                        maxInSampleCount = samples.length;
 
                     /*
                      * Convey the timeStamp so that it can be set to the Buffers
@@ -910,35 +977,16 @@ private int readInputPushBufferStreams(
                      * timeStamps, only use the first meaningful timestamp for
                      * now.
                      */
-                    if (inputSampleDesc.getTimeStamp() == Buffer.TIME_UNKNOWN)
-                        inputSampleDesc.setTimeStamp(buffer.getTimeStamp());
+                    if (inSampleDesc.getTimeStamp() == Buffer.TIME_UNKNOWN)
+                        inSampleDesc.setTimeStamp(buffer.getTimeStamp());
 
                     continue;
                 }
             }
 
-            inputSamples[i] = null;
+            inSamples[i] = null;
         }
-        return maxInputSampleCount;
-    }
-
-    /**
-     * Reads an integer from a specific series of bytes starting the reading at
-     * a specific offset in it.
-     *
-     * @param input the series of bytes to read an integer from
-     * @param inputOffset the offset in <tt>input</tt> at which the reading of
-     * the integer is to start
-     * @return an integer read from the specified series of bytes starting at
-     * the specified offset in it
-     */
-    private static int readInt(byte[] input, int inputOffset)
-    {
-        return
-            (input[inputOffset + 3] << 24)
-                | ((input[inputOffset + 2] & 0xFF) << 16)
-                | ((input[inputOffset + 1] & 0xFF) << 8)
-                | (input[inputOffset] & 0xFF);
+        return maxInSampleCount;
     }
 
     /**
@@ -946,21 +994,21 @@ private static int readInt(byte[] input, int inputOffset)
      * collection of such streams to which this instance pushes the data for
      * audio mixing it reads from its input <tt>SourceStream</tt>s.
      *
-     * @param outputStream the <tt>AudioMixingPushBufferStream</tt> to remove
+     * @param outStream the <tt>AudioMixingPushBufferStream</tt> to remove
      * from the collection of such streams to which this instance pushes the
      * data for audio mixing it reads from its input <tt>SourceStream</tt>s
-     * @throws IOException if <tt>outputStream</tt> was the last
+     * @throws IOException if <tt>outStream</tt> was the last
      * <tt>AudioMixingPushBufferStream</tt> and the <tt>AudioMixer</tt> failed
      * to stop
      */
-    void removeOutputStream(AudioMixingPushBufferStream outputStream)
+    void removeOutStream(AudioMixingPushBufferStream outStream)
         throws IOException
     {
-        synchronized (outputStreams)
+        synchronized (outStreams)
         {
-            if ((outputStream != null)
-                    && outputStreams.remove(outputStream)
-                    && outputStreams.isEmpty())
+            if ((outStream != null)
+                    && outStreams.remove(outStream)
+                    && outStreams.isEmpty())
                 audioMixer.stop(this);
         }
     }
@@ -974,96 +1022,107 @@ void removeOutputStream(AudioMixingPushBufferStream outputStream)
      * the output mix are not pushed to the
      * <tt>AudioMixingPushBufferStream</tt>.
      *
-     * @param outputStream the <tt>AudioMixingPushBufferStream</tt> to push the
+     * @param outStream the <tt>AudioMixingPushBufferStream</tt> to push the
      * specified set of audio samples to
-     * @param inputSampleDesc the set of audio samples to be pushed to
-     * <tt>outputStream</tt> for audio mixing
-     * @param maxInputSampleCount the maximum number of audio samples available
-     * in <tt>inputSamples</tt>
+     * @param inSampleDesc the set of audio samples to be pushed to
+     * <tt>outStream</tt> for audio mixing
+     * @param maxInSampleCount the maximum number of audio samples available
+     * in <tt>inSamples</tt>
      */
-    private void setInputSamples(
-        AudioMixingPushBufferStream outputStream,
-        InputSampleDesc inputSampleDesc,
-        int maxInputSampleCount)
+    private void setInSamples(
+            AudioMixingPushBufferStream outStream,
+            InSampleDesc inSampleDesc,
+            int maxInSampleCount)
     {
-        int[][] inputSamples = inputSampleDesc.inputSamples;
-        InputStreamDesc[] inputStreams = inputSampleDesc.inputStreams;
+        int[][] inSamples = inSampleDesc.inSamples;
+        InStreamDesc[] inStreams = inSampleDesc.inStreams;
 
-        inputSamples = inputSamples.clone();
+        inSamples = inSamples.clone();
 
         CaptureDevice captureDevice = audioMixer.captureDevice;
-        AudioMixingPushBufferDataSource outputDataSource
-            = outputStream.getDataSource();
-        boolean outputDataSourceIsSendingDTMF
+        AudioMixingPushBufferDataSource outDataSource
+            = outStream.getDataSource();
+        boolean outDataSourceIsSendingDTMF
             = (captureDevice instanceof AudioMixingPushBufferDataSource)
-                ? outputDataSource.isSendingDTMF()
+                ? outDataSource.isSendingDTMF()
                 : false;
-        boolean outputDataSourceIsMute = outputDataSource.isMute();
+        boolean outDataSourceIsMute = outDataSource.isMute();
 
-        for (int i = 0; i < inputSamples.length; i++)
+        for (int i = 0, o = 0; i < inSamples.length; i++)
         {
-            InputStreamDesc inputStreamDesc = inputStreams[i];
-            DataSource inputDataSource
-                = inputStreamDesc.inputDataSourceDesc.inputDataSource;
+            InStreamDesc inStreamDesc = inStreams[i];
+            DataSource inDataSource
+                = inStreamDesc.inDataSourceDesc.inDataSource;
 
-            if (outputDataSourceIsSendingDTMF
-                    && (inputDataSource == captureDevice))
+            if (outDataSourceIsSendingDTMF && (inDataSource == captureDevice))
             {
-                PushBufferStream inputStream
-                    = (PushBufferStream) inputStreamDesc.getInputStream();
-                AudioFormat inputStreamFormat
-                    = (AudioFormat) inputStream.getFormat();
-
-                double sampleRate = inputStreamFormat.getSampleRate();
-                int sampleSizeInBits = inputStreamFormat.getSampleSizeInBits();
-
+                PushBufferStream inStream
+                    = (PushBufferStream) inStreamDesc.getInStream();
+                AudioFormat inStreamFormat = (AudioFormat) inStream.getFormat();
                 // Generate the inband DTMF signal.
-                inputSamples[i]
-                    = outputDataSource.getNextToneSignal(
-                            sampleRate,
-                            sampleSizeInBits);
-                if (maxInputSampleCount < inputSamples[i].length)
-                    maxInputSampleCount = inputSamples[i].length;
+                int[] nextToneSignal
+                    = outDataSource.getNextToneSignal(
+                            inStreamFormat.getSampleRate(),
+                            inStreamFormat.getSampleSizeInBits());
+
+                inSamples[i] = nextToneSignal;
+                if (maxInSampleCount < nextToneSignal.length)
+                    maxInSampleCount = nextToneSignal.length;
             }
-            else if (outputDataSource.equals(
-                        inputStreamDesc.getOutputDataSource())
-                    || (outputDataSourceIsMute
-                            && (inputDataSource == captureDevice)))
+            else if (outDataSource.equals(inStreamDesc.getOutDataSource())
+                    || (outDataSourceIsMute && (inDataSource == captureDevice)))
             {
-                inputSamples[i] = null;
+                inSamples[i] = null;
+            }
+
+            /*
+             * Have the samples of the contributing streams at the head of the
+             * sample set (and the non-contributing at the tail) in order to
+             * optimize determining the number of contributing streams later on
+             * and, consequently, the mixing.
+             */
+            int[] inStreamSamples = inSamples[i];
+
+            if (inStreamSamples != null)
+            {
+                if (i != o)
+                {
+                    inSamples[o] = inStreamSamples;
+                    inSamples[i] = null;
+                }
+                o++;
             }
         }
 
-        outputStream.setInputSamples(
-                inputSamples,
-                maxInputSampleCount,
-                inputSampleDesc.getTimeStamp());
+        outStream.setInSamples(
+                inSamples,
+                maxInSampleCount,
+                inSampleDesc.getTimeStamp());
     }
 
     /**
-     * Sets the <tt>SourceStream</tt>s (in the form of <tt>InputStreamDesc</tt>)
+     * Sets the <tt>SourceStream</tt>s (in the form of <tt>InStreamDesc</tt>)
      * from which this instance is to read audio samples and push them to the
      * <tt>AudioMixingPushBufferStream</tt>s for audio mixing.
      *
-     * @param inputStreams the <tt>SourceStream</tt>s (in the form of
-     * <tt>InputStreamDesc</tt>) from which this instance is to read audio
+     * @param inStreams the <tt>SourceStream</tt>s (in the form of
+     * <tt>InStreamDesc</tt>) from which this instance is to read audio
      * samples and push them to the <tt>AudioMixingPushBufferStream</tt>s for
      * audio mixing
      */
-    void setInputStreams(Collection<InputStreamDesc> inputStreams)
+    void setInStreams(Collection<InStreamDesc> inStreams)
     {
-        InputStreamDesc[] oldValue;
-        InputStreamDesc[] newValue
-            = (null == inputStreams)
+        InStreamDesc[] oldValue;
+        InStreamDesc[] newValue
+            = (null == inStreams)
                 ? null
-                : inputStreams.toArray(
-                        new InputStreamDesc[inputStreams.size()]);
+                : inStreams.toArray(new InStreamDesc[inStreams.size()]);
 
-        synchronized (inputStreamsSyncRoot)
+        synchronized (inStreamsSyncRoot)
         {
-            oldValue = this.inputStreams;
+            oldValue = this.inStreams;
 
-            this.inputStreams = newValue;
+            this.inStreams = newValue;
         }
 
         boolean valueIsChanged = !Arrays.equals(oldValue, newValue);
@@ -1078,36 +1137,36 @@ void setInputStreams(Collection<InputStreamDesc> inputStreams)
 
             boolean skippedForTransferHandler = false;
 
-            for (InputStreamDesc inputStreamDesc : newValue)
+            for (InStreamDesc inStreamDesc : newValue)
             {
-                SourceStream inputStream = inputStreamDesc.getInputStream();
+                SourceStream inStream = inStreamDesc.getInStream();
 
-                if (!(inputStream instanceof PushBufferStream))
+                if (!(inStream instanceof PushBufferStream))
                     continue;
                 if (!skippedForTransferHandler)
                 {
                     skippedForTransferHandler = true;
                     continue;
                 }
-                if (!(inputStream instanceof CachingPushBufferStream))
+                if (!(inStream instanceof CachingPushBufferStream))
                 {
-                    PushBufferStream cachingInputStream
+                    PushBufferStream cachingInStream
                         = new CachingPushBufferStream(
-                                (PushBufferStream) inputStream);
+                                (PushBufferStream) inStream);
 
-                    inputStreamDesc.setInputStream(cachingInputStream);
+                    inStreamDesc.setInStream(cachingInStream);
                     if (logger.isTraceEnabled())
                         logger.trace(
                                 "Created CachingPushBufferStream"
                                     + " with hashCode "
-                                    + cachingInputStream.hashCode()
-                                    + " for inputStream with hashCode "
-                                    + inputStream.hashCode());
+                                    + cachingInStream.hashCode()
+                                    + " for inStream with hashCode "
+                                    + inStream.hashCode());
                 }
             }
 
             setTransferHandler(newValue, transferHandler);
-            equalizeInputStreamBufferLength();
+            equalizeInStreamBufferLength();
 
             if (logger.isTraceEnabled())
             {
@@ -1117,15 +1176,13 @@ void setInputStreams(Collection<InputStreamDesc> inputStreams)
 
                 if (difference > 0)
                     logger.trace(
-                            "Added "
-                                + difference
-                                + " inputStream(s) and the total is "
+                            "Added " + difference
+                                + " inStream(s) and the total is "
                                 + newValueLength);
                 else if (difference < 0)
                     logger.trace(
-                            "Removed "
-                                + difference
-                                + " inputStream(s) and the total is "
+                            "Removed " + difference
+                                + " inStream(s) and the total is "
                                 + newValueLength);
             }
         }
@@ -1144,47 +1201,46 @@ else if (difference < 0)
      */
     public void setTransferHandler(BufferTransferHandler transferHandler)
     {
-        throw
-            new UnsupportedOperationException(
-                    AudioMixerPushBufferStream.class.getSimpleName()
-                        + ".setTransferHandler(BufferTransferHandler)");
+        throw new UnsupportedOperationException(
+                AudioMixerPushBufferStream.class.getSimpleName()
+                    + ".setTransferHandler(BufferTransferHandler)");
     }
 
     /**
      * Sets a specific <tt>BufferTransferHandler</tt> to a specific collection
-     * of <tt>SourceStream</tt>s (in the form of <tt>InputStreamDesc</tt>)
+     * of <tt>SourceStream</tt>s (in the form of <tt>InStreamDesc</tt>)
      * abstracting the differences among the various types of
      * <tt>SourceStream</tt>s.
      *
-     * @param inputStreams the input <tt>SourceStream</tt>s to which the
+     * @param inStreams the input <tt>SourceStream</tt>s to which the
      * specified <tt>BufferTransferHandler</tt> is to be set
      * @param transferHandler the <tt>BufferTransferHandler</tt> to be set to
-     * the specified <tt>inputStreams</tt>
+     * the specified <tt>inStreams</tt>
      */
     private void setTransferHandler(
-        InputStreamDesc[] inputStreams,
-        BufferTransferHandler transferHandler)
+            InStreamDesc[] inStreams,
+            BufferTransferHandler transferHandler)
     {
-        if ((inputStreams == null) || (inputStreams.length <= 0))
+        if ((inStreams == null) || (inStreams.length <= 0))
             return;
 
         boolean transferHandlerIsSet = false;
 
-        for (InputStreamDesc inputStreamDesc : inputStreams)
+        for (InStreamDesc inStreamDesc : inStreams)
         {
-            SourceStream inputStream = inputStreamDesc.getInputStream();
+            SourceStream inStream = inStreamDesc.getInStream();
 
-            if (inputStream instanceof PushBufferStream)
+            if (inStream instanceof PushBufferStream)
             {
-                BufferTransferHandler inputStreamTransferHandler;
-                PushBufferStream inputPushBufferStream
-                    = (PushBufferStream) inputStream;
+                BufferTransferHandler inStreamTransferHandler;
+                PushBufferStream inPushBufferStream
+                    = (PushBufferStream) inStream;
 
                 if (transferHandler == null)
-                    inputStreamTransferHandler = null;
+                    inStreamTransferHandler = null;
                 else if (transferHandlerIsSet)
                 {
-                    inputStreamTransferHandler = new BufferTransferHandler()
+                    inStreamTransferHandler = new BufferTransferHandler()
                     {
                         public void transferData(PushBufferStream stream)
                         {
@@ -1198,15 +1254,15 @@ public void transferData(PushBufferStream stream)
                 }
                 else
                 {
-                    inputStreamTransferHandler
+                    inStreamTransferHandler
                         = new StreamSubstituteBufferTransferHandler(
-                                    transferHandler,
-                                    inputPushBufferStream,
-                                    this);
+                                transferHandler,
+                                inPushBufferStream,
+                                this);
                 }
 
-                inputPushBufferStream.setTransferHandler(
-                        inputStreamTransferHandler);
+                inPushBufferStream.setTransferHandler(
+                        inStreamTransferHandler);
 
                 transferHandlerIsSet = true;
             }
@@ -1234,180 +1290,35 @@ protected void transferData(Buffer buffer)
             throw new UndeclaredThrowableException(ex);
         }
 
-        InputSampleDesc inputSampleDesc = (InputSampleDesc) buffer.getData();
-        int[][] inputSamples = inputSampleDesc.inputSamples;
-        int maxInputSampleCount = buffer.getLength();
+        InSampleDesc inSampleDesc = (InSampleDesc) buffer.getData();
+        int[][] inSamples = inSampleDesc.inSamples;
+        int maxInSampleCount = buffer.getLength();
 
-        if ((inputSamples == null)
-                || (inputSamples.length == 0)
-                || (maxInputSampleCount <= 0))
+        if ((inSamples == null)
+                || (inSamples.length == 0)
+                || (maxInSampleCount <= 0))
             return;
 
-        AudioMixingPushBufferStream[] outputStreams;
+        AudioMixingPushBufferStream[] outStreams;
 
-        synchronized (this.outputStreams)
+        synchronized (this.outStreams)
         {
-            outputStreams
-                = this.outputStreams.toArray(
+            outStreams
+                = this.outStreams.toArray(
                         new AudioMixingPushBufferStream[
-                                this.outputStreams.size()]);
+                                this.outStreams.size()]);
         }
-        for (AudioMixingPushBufferStream outputStream : outputStreams)
-            setInputSamples(outputStream, inputSampleDesc, maxInputSampleCount);
+        for (AudioMixingPushBufferStream outStream : outStreams)
+            setInSamples(outStream, inSampleDesc, maxInSampleCount);
 
         /*
          * The input samples have already been delivered to the output streams
          * and are no longer necessary.
          */
-        for (int i = 0; i < inputSamples.length; i++)
-        {
-            deallocateIntArray(inputSamples[i]);
-            inputSamples[i] = null;
-        }
-    }
-
-    private int[] validateIntArraySize(Buffer buffer, int newSize)
-    {
-        Object data = buffer.getData();
-        int[] intArray;
-
-        if (data instanceof int[])
-        {
-            intArray = (int[]) data;
-            if (intArray.length < newSize)
-            {
-                deallocateIntArray(intArray);
-                intArray = null;
-            }
-        }
-        else
-            intArray = null;
-        if (intArray == null)
-        {
-            intArray = allocateIntArray(newSize);
-            buffer.setData(intArray);
-        }
-        return intArray;
-    }
-
-    /**
-     * Describes a specific set of audio samples read from a specific set of
-     * input streams specified by their <tt>InputStreamDesc</tt>s.
-     */
-    private static class InputSampleDesc
-    {
-        /**
-         * The <tt>Buffer</tt> into which media data is to be read from
-         * {@link #inputStreams}.
-         */
-        private SoftReference<Buffer> buffer;
-
-        /**
-         * The set of audio samples read from {@link #inputStreams}.
-         */
-        public final int[][] inputSamples;
-
-        /**
-         * The set of input streams from which {@link #inputSamples} were read.
-         */
-        public final InputStreamDesc[] inputStreams;
-
-        /**
-         * The time stamp of <tt>inputSamples</tt> to be reported in the
-         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
-         * mixes are read from them.
-         */
-        private long timeStamp = Buffer.TIME_UNKNOWN;
-
-        /**
-         * Initializes a new <tt>InputSampleDesc</tt> instance which is to
-         * describe a specific set of audio samples read from a specific set of
-         * input streams specified by their <tt>InputStreamDesc</tt>s.
-         *
-         * @param inputSamples the set of audio samples read from
-         * <tt>inputStreams</tt>
-         * @param inputStreams the set of input streams from which
-         * <tt>inputSamples</tt> were read
-         */
-        public InputSampleDesc(
-                int[][] inputSamples,
-                InputStreamDesc[] inputStreams)
+        for (int i = 0; i < inSamples.length; i++)
         {
-            this.inputSamples = inputSamples;
-            this.inputStreams = inputStreams;
-        }
-
-        /**
-         * Gets the <tt>Buffer</tt> into which media data is to be read from the
-         * input streams associated with this instance.
-         *
-         * @param create the indicator which determines whether the
-         * <tt>Buffer</tt> is to be created in case it does not exist
-         * @return the <tt>Buffer</tt> into which media data is to be read from
-         * the input streams associated with this instance
-         */
-        public Buffer getBuffer(boolean create)
-        {
-            Buffer buffer = (this.buffer == null) ? null : this.buffer.get();
-
-            if ((buffer == null) && create)
-            {
-                buffer = new Buffer();
-                setBuffer(buffer);
-            }
-            return buffer;
-        }
-
-        /**
-         * Gets the time stamp of <tt>inputSamples</tt> to be reported in the
-         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
-         * mixes are read from them.
-         *
-         * @return the time stamp of <tt>inputSamples</tt> to be reported in the
-         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
-         * mixes are read from them
-         */
-        public long getTimeStamp()
-        {
-            return timeStamp;
-        }
-
-        /**
-         * Sets the <tt>Buffer</tt> into which media data is to be read from the
-         * input streams associated with this instance.
-         *
-         * @param buffer the <tt>Buffer</tt> into which media data is to be read
-         * from the input streams associated with this instance
-         */
-        public void setBuffer(Buffer buffer)
-        {
-            this.buffer
-                = (buffer == null) ? null : new SoftReference<Buffer>(buffer);
-        }
-
-        /**
-         * Sets the time stamp of <tt>inputSamples</tt> to be reported in the
-         * <tt>Buffer</tt>s of the <tt>AudioMixingPushBufferStream</tt>s when
-         * mixes are read from them.
-         *
-         * @param timeStamp the time stamp of <tt>inputSamples</tt> to be
-         * reported in the <tt>Buffer</tt>s of the
-         * <tt>AudioMixingPushBufferStream</tt>s when mixes are read from them
-         */
-        public void setTimeStamp(long timeStamp)
-        {
-            if (this.timeStamp == Buffer.TIME_UNKNOWN)
-                this.timeStamp = timeStamp;
-            else
-            {
-                /*
-                 * Setting the timeStamp more than once does not make sense
-                 * because the inputStreams will report different timeStamps so
-                 * only one should be picked up where the very reading from
-                 * inputStreams takes place.
-                 */
-                throw new IllegalStateException("timeStamp");
-            }
+            audioMixer.intArrayCache.deallocateIntArray(inSamples[i]);
+            inSamples[i] = null;
         }
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferDataSource.java b/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferDataSource.java
index 97b70379..802089af 100644
--- a/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferDataSource.java
+++ b/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferDataSource.java
@@ -24,7 +24,7 @@
  * <tt>PushBufferStream</tt> containing the result of the audio mixing of
  * <tt>DataSource</tt>s.
  *
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
  */
 public class AudioMixingPushBufferDataSource
     extends PushBufferDataSource
@@ -45,7 +45,7 @@ public class AudioMixingPushBufferDataSource
      * <tt>DataSource</tt>s and pushing the data of this output
      * <tt>PushBufferDataSource</tt>.
      */
-    private final AudioMixer audioMixer;
+    final AudioMixer audioMixer;
 
     /**
      * The indicator which determines whether this <tt>DataSource</tt> is
@@ -53,12 +53,18 @@ public class AudioMixingPushBufferDataSource
      */
     private boolean connected;
 
+    /**
+     * The indicator which determines whether this <tt>DataSource</tt> is set
+     * to transmit "silence" instead of the actual media.
+     */
+    private boolean mute = false;
+
     /**
      * The one and only <tt>PushBufferStream</tt> this
      * <tt>PushBufferDataSource</tt> provides to its clients and containing the
      * result of the audio mixing performed by <tt>audioMixer</tt>.
      */
-    private AudioMixingPushBufferStream outputStream;
+    private AudioMixingPushBufferStream outStream;
 
     /**
      * The indicator which determines whether this <tt>DataSource</tt> is
@@ -66,16 +72,11 @@ public class AudioMixingPushBufferDataSource
      */
     private boolean started;
 
-    /**
-     * The indicator which determines whether this <tt>DataSource</tt> is set
-     * to transmit "silence" instead of the actual media.
-     */
-    private boolean mute = false;
-
     /**
      * The tones to send via inband DTMF, if not empty.
      */
-    private LinkedList<DTMFInbandTone> tones = new LinkedList<DTMFInbandTone>();
+    private final LinkedList<DTMFInbandTone> tones
+        = new LinkedList<DTMFInbandTone>();
 
     /**
      * Initializes a new <tt>AudioMixingPushBufferDataSource</tt> instance which
@@ -91,30 +92,30 @@ public AudioMixingPushBufferDataSource(AudioMixer audioMixer)
         this.audioMixer = audioMixer;
     }
 
+    /**
+     * Adds a new inband DTMF tone to send.
+     *
+     * @param tone the DTMF tone to send.
+     */
+    public void addDTMF(DTMFInbandTone tone)
+    {
+        tones.add(tone);
+    }
+
     /**
      * Adds a new input <tt>DataSource</tt> to be mixed by the associated
      * <tt>AudioMixer</tt> of this instance and to not have its audio
      * contributions included in the mixing output represented by this
      * <tt>DataSource</tt>.
      *
-     * @param inputDataSource a <tt>DataSource</tt> to be added for mixing to
+     * @param inDataSource a <tt>DataSource</tt> to be added for mixing to
      * the <tt>AudioMixer</tt> associate with this instance and to not have its
      * audio contributions included in the mixing output represented by this
      * <tt>DataSource</tt>
      */
-    public void addInputDataSource(DataSource inputDataSource)
-    {
-        audioMixer.addInputDataSource(inputDataSource, this);
-    }
-
-    /**
-     * The input <tt>DataSource</tt> has been updated.
-     * @param inputDataSource the <tt>DataSource</tt> that was updated.
-     */
-    public void updateInputDataSource(DataSource inputDataSource)
+    public void addInDataSource(DataSource inDataSource)
     {
-        // just update the input streams
-        audioMixer.getOutputStream();
+        audioMixer.addInDataSource(inDataSource, this);
     }
 
     /**
@@ -155,7 +156,7 @@ public synchronized void disconnect()
 
         if (connected)
         {
-            outputStream = null;
+            outStream = null;
             connected = false;
 
             audioMixer.disconnect();
@@ -240,12 +241,9 @@ else if ((formatControls == null) || (formatControls.length < 1))
             Object[] controls = new Object[1 + formatControls.length];
 
             controls[0] = bufferControl;
-            System
-                .arraycopy(
-                    formatControls,
-                    0,
-                    controls,
-                    1,
+            System.arraycopy(
+                    formatControls, 0,
+                    controls, 1,
                     formatControls.length);
             return controls;
         }
@@ -278,6 +276,20 @@ public FormatControl[] getFormatControls()
         return audioMixer.getFormatControls();
     }
 
+    /**
+     * Gets the next inband DTMF tone signal.
+     *
+     * @param sampleRate The sampling frequency (codec clock rate) in Hz of the
+     * stream which will encapsulate this signal.
+     * @param sampleSizeInBits The size of each sample (8 for a byte, 16 for a
+     * short and 32 for an int)
+     * @return The data array containing the DTMF signal.
+     */
+    public int[] getNextToneSignal(double sampleRate, int sampleSizeInBits)
+    {
+        return tones.poll().getAudioSamples(sampleRate, sampleSizeInBits);
+    }
+
     /**
      * Implements {@link PushBufferDataSource#getStreams()}. Gets a
      * <tt>PushBufferStream</tt> which reads data from the associated
@@ -290,38 +302,69 @@ public FormatControl[] getFormatControls()
     @Override
     public synchronized PushBufferStream[] getStreams()
     {
-        if (connected && (outputStream == null))
+        if (connected && (outStream == null))
         {
-            AudioMixerPushBufferStream audioMixerOutputStream
-                = audioMixer.getOutputStream();
+            AudioMixerPushBufferStream audioMixerOutStream
+                = audioMixer.getOutStream();
 
-            if (audioMixerOutputStream != null)
+            if (audioMixerOutStream != null)
             {
-                outputStream
+                outStream
                     = new AudioMixingPushBufferStream(
-                            audioMixerOutputStream,
+                            audioMixerOutStream,
                             this);
                 if (started)
                     try
                     {
-                        outputStream.start();
+                        outStream.start();
                     }
                     catch (IOException ioex)
                     {
-                        logger
-                            .error(
+                        logger.error(
                                 "Failed to start "
-                                    + outputStream.getClass().getSimpleName()
-                                    + " with hashCode "
-                                    + outputStream.hashCode(),
+                                    + outStream.getClass().getSimpleName()
+                                    + " with hashCode " + outStream.hashCode(),
                                 ioex);
                     }
             }
         }
         return
-            (outputStream == null)
+            (outStream == null)
                 ? new PushBufferStream[0]
-                : new PushBufferStream[] { outputStream };
+                : new PushBufferStream[] { outStream };
+    }
+
+    /**
+     * Determines whether this <tt>DataSource</tt> is mute.
+     *
+     * @return <tt>true</tt> if this <tt>DataSource</tt> is mute; otherwise,
+     *         <tt>false</tt>
+     */
+    public boolean isMute()
+    {
+        return mute;
+    }
+
+    /**
+     * Determines whether this <tt>DataSource</tt> sends a DTMF tone.
+     *
+     * @return <tt>true</tt> if this <tt>DataSource</tt> is sending a DTMF tone;
+     * otherwise, <tt>false</tt>.
+     */
+    public boolean isSendingDTMF()
+    {
+        return !tones.isEmpty();
+    }
+
+    /**
+     * Sets the mute state of this <tt>DataSource</tt>.
+     *
+     * @param mute <tt>true</tt> to mute this <tt>DataSource</tt>; otherwise,
+     *            <tt>false</tt>
+     */
+    public void setMute(boolean mute)
+    {
+        this.mute = mute;
     }
 
     /**
@@ -340,8 +383,8 @@ public synchronized void start()
         if (!started)
         {
             started = true;
-            if (outputStream != null)
-                outputStream.start();
+            if (outStream != null)
+                outStream.start();
         }
     }
 
@@ -361,72 +404,19 @@ public synchronized void stop()
         if (started)
         {
             started = false;
-            if (outputStream != null)
-                outputStream.stop();
-        }
-    }
-
-    /**
-     * Determines whether this <tt>DataSource</tt> is mute.
-     *
-     * @return <tt>true</tt> if this <tt>DataSource</tt> is mute; otherwise,
-     *         <tt>false</tt>
-     */
-    public boolean isMute()
-    {
-        return this.mute;
-    }
-
-    /**
-     * Sets the mute state of this <tt>DataSource</tt>.
-     *
-     * @param mute <tt>true</tt> to mute this <tt>DataSource</tt>; otherwise,
-     *            <tt>false</tt>
-     */
-    public void setMute(boolean mute)
-    {
-        if (this.mute != mute)
-        {
-            this.mute = mute;
+            if (outStream != null)
+                outStream.stop();
         }
     }
 
     /**
-     * Adds a new inband DTMF tone to send.
-     *
-     * @param tone the DTMF tone to send.
-     */
-    public void addDTMF(DTMFInbandTone tone)
-    {
-        this.tones.add(tone);
-    }
-
-    /**
-     * Determines whether this <tt>DataSource</tt> sends a DTMF tone.
-     *
-     * @return <tt>true</tt> if this <tt>DataSource</tt> is sending a DTMF tone;
-     * otherwise, <tt>false</tt>.
-     */
-    public boolean isSendingDTMF()
-    {
-        return !this.tones.isEmpty();
-    }
-
-    /**
-     * Gets the next inband DTMF tone signal.
-     *
-     * @param samplingFrequency The sampling frequency (codec clock rate) in Hz
-     * of the stream which will encapsulate this signal.
-     * @param sampleSizeInBits The size of each sample (8 for a byte, 16 for a
-     * short and 32 for an int)
+     * The input <tt>DataSource</tt> has been updated.
      *
-     * @return The data array containing the DTMF signal.
+     * @param inDataSource the <tt>DataSource</tt> that was updated.
      */
-    public int[] getNextToneSignal(
-            double samplingFrequency,
-            int sampleSizeInBits)
+    public void updateInDataSource(DataSource inDataSource)
     {
-        DTMFInbandTone tone = tones.poll();
-        return tone.getAudioSamples(samplingFrequency, sampleSizeInBits);
+        // just update the input streams
+        audioMixer.getOutStream();
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferStream.java b/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferStream.java
index cac446f4..a2f812d0 100644
--- a/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferStream.java
+++ b/src/org/jitsi/impl/neomedia/conference/AudioMixingPushBufferStream.java
@@ -7,6 +7,7 @@
 package org.jitsi.impl.neomedia.conference;
 
 import java.io.*;
+import java.util.*;
 
 import javax.media.*;
 import javax.media.format.*;
@@ -34,6 +35,36 @@ public class AudioMixingPushBufferStream
     private static final Logger logger
         = Logger.getLogger(AudioMixingPushBufferStream.class);
 
+    /**
+     * Gets the maximum possible value for an audio sample of a specific
+     * <tt>AudioFormat</tt>.
+     *
+     * @param outFormat the <tt>AudioFormat</tt> of which to get the maximum
+     * possible value for an audio sample
+     * @return the maximum possible value for an audio sample of the specified
+     * <tt>AudioFormat</tt>
+     * @throws UnsupportedFormatException if the specified <tt>outFormat</tt>
+     * is not supported by the underlying implementation
+     */
+    private static int getMaxOutSample(AudioFormat outFormat)
+        throws UnsupportedFormatException
+    {
+        switch(outFormat.getSampleSizeInBits())
+        {
+        case 8:
+            return Byte.MAX_VALUE;
+        case 16:
+            return Short.MAX_VALUE;
+        case 32:
+            return Integer.MAX_VALUE;
+        case 24:
+        default:
+            throw new UnsupportedFormatException(
+                    "Format.getSampleSizeInBits()",
+                    outFormat);
+        }
+    }
+
     /**
      * The <tt>AudioMixerPushBufferStream</tt> which reads data from the input
      * <tt>DataSource</tt>s and pushes it to this instance to be mixed.
@@ -51,23 +82,23 @@ public class AudioMixingPushBufferStream
      * The collection of input audio samples still not mixed and read through
      * this <tt>AudioMixingPushBufferStream</tt>.
      */
-    private int[][] inputSamples;
+    private int[][] inSamples;
 
     /**
      * The maximum number of per-stream audio samples available through
-     * <tt>inputSamples</tt>.
+     * <tt>inSamples</tt>.
      */
-    private int maxInputSampleCount;
+    private int maxInSampleCount;
 
     /**
      * The <tt>Object</tt> which synchronizes the access to the data to be read
-     * from this <tt>PushBufferStream</tt> i.e. to {@link #inputSamples},
-     * {@link #maxInputSampleCount} and {@link #timeStamp}.
+     * from this <tt>PushBufferStream</tt> i.e. to {@link #inSamples},
+     * {@link #maxInSampleCount} and {@link #timeStamp}.
      */
     private final Object readSyncRoot = new Object();
 
     /**
-     * The time stamp of {@link #inputSamples} to be reported in the specified
+     * The time stamp of {@link #inSamples} to be reported in the specified
      * <tt>Buffer</tt> when data is read from this instance.
      */
     private long timeStamp;
@@ -93,8 +124,8 @@ public class AudioMixingPushBufferStream
      * input data to not be mixed in the output of the new instance
      */
     AudioMixingPushBufferStream(
-        AudioMixerPushBufferStream audioMixerStream,
-        AudioMixingPushBufferDataSource dataSource)
+            AudioMixerPushBufferStream audioMixerStream,
+            AudioMixingPushBufferDataSource dataSource)
     {
         this.audioMixerStream = audioMixerStream;
         this.dataSource = dataSource;
@@ -111,7 +142,7 @@ public class AudioMixingPushBufferStream
     public boolean endOfStream()
     {
         /*
-         * TODO If the inputSamples haven't been consumed yet, don't report the
+         * TODO If the inSamples haven't been consumed yet, don't report the
          * end of this stream even if the wrapped stream has reached its end.
          */
         return audioMixerStream.endOfStream();
@@ -170,118 +201,102 @@ public AudioFormat getFormat()
         return audioMixerStream.getFormat();
     }
 
-    /**
-     * Gets the maximum possible value for an audio sample of a specific
-     * <tt>AudioFormat</tt>.
-     *
-     * @param outputFormat the <tt>AudioFormat</tt> of which to get the maximum
-     * possible value for an audio sample
-     * @return the maximum possible value for an audio sample of the specified
-     * <tt>AudioFormat</tt>
-     * @throws UnsupportedFormatException if the specified <tt>outputFormat</tt>
-     * is not supported by the underlying implementation
-     */
-    private static int getMaxOutputSample(AudioFormat outputFormat)
-        throws UnsupportedFormatException
-    {
-        switch(outputFormat.getSampleSizeInBits())
-        {
-        case 8:
-            return Byte.MAX_VALUE;
-        case 16:
-            return Short.MAX_VALUE;
-        case 32:
-            return Integer.MAX_VALUE;
-        case 24:
-        default:
-            throw
-                new UnsupportedFormatException(
-                        "Format.getSampleSizeInBits()",
-                        outputFormat);
-        }
-    }
-
     /**
      * Mixes as in audio mixing a specified collection of audio sample sets and
      * returns the resulting mix audio sample set in a specific
      * <tt>AudioFormat</tt>.
      *
-     * @param inputSamples the collection of audio sample sets to be mixed into
+     * @param inSamples the collection of audio sample sets to be mixed into
      * one audio sample set in the sense of audio mixing
-     * @param outputFormat the <tt>AudioFormat</tt> in which the resulting mix
-     * audio sample set is to be produced
-     * @param outputSampleCount the size of the resulting mix audio sample set
+     * @param outFormat the <tt>AudioFormat</tt> in which the resulting mix
+     * audio sample set is to be produced. The <tt>format</tt> property of the
+     * specified <tt>outBuffer</tt> is expected to be set to the same value but
+     * it is provided as a method argument in order to avoid casting from
+     * <tt>Format</tt> to <tt>AudioFormat</tt>.
+     * @param outSampleCount the size of the resulting mix audio sample set
      * to be produced
      * @return the resulting audio sample set of the audio mixing of the
      * specified input audio sample sets
      */
-    private static int[] mix(
-        int[][] inputSamples,
-        AudioFormat outputFormat,
-        int outputSampleCount)
+    private int[] mix(
+            int[][] inSamples,
+            AudioFormat outFormat,
+            int outSampleCount)
     {
-        int[] outputSamples = new int[outputSampleCount];
+        int[] outSamples
+            = dataSource.audioMixer.intArrayCache.allocateIntArray(
+                    outSampleCount);
 
         /*
          * The trivial case of performing audio mixing the audio of a single
          * stream. Then there is nothing to mix and the input becomes the
          * output.
          */
-        if (inputSamples.length == 1)
+        if ((inSamples.length == 1) || (inSamples[1] == null))
         {
-            int[] inputStreamSamples = inputSamples[0];
+            int[] inStreamSamples = inSamples[0];
+            int inStreamSampleCount;
 
-            if (inputStreamSamples != null)
+            if (inStreamSamples == null)
             {
+                inStreamSampleCount = 0;
+            }
+            else
+            {
+                inStreamSampleCount
+                    = Math.min(inStreamSamples.length, outSampleCount);
                 System.arraycopy(
-                        inputStreamSamples, 0,
-                        outputSamples, 0,
-                        inputStreamSamples.length);
+                        inStreamSamples, 0,
+                        outSamples, 0,
+                        inStreamSampleCount);
             }
-            return outputSamples;
+            if (inStreamSampleCount != outSampleCount)
+                Arrays.fill(outSamples, inStreamSampleCount, outSampleCount, 0);
+            return outSamples;
         }
 
-        int maxOutputSample;
+        int maxOutSample;
 
         try
         {
-            maxOutputSample = getMaxOutputSample(outputFormat);
+            maxOutSample = getMaxOutSample(outFormat);
         }
         catch (UnsupportedFormatException ufex)
         {
             throw new UnsupportedOperationException(ufex);
         }
 
-        for (int[] inputStreamSamples : inputSamples)
+        Arrays.fill(outSamples, 0, outSampleCount, 0);
+        for (int[] inStreamSamples : inSamples)
         {
-            if (inputStreamSamples == null)
+            if (inStreamSamples == null)
                 continue;
 
-            int inputStreamSampleCount = inputStreamSamples.length;
+            int inStreamSampleCount
+                = Math.min(inStreamSamples.length, outSampleCount);
 
-            if (inputStreamSampleCount <= 0)
+            if (inStreamSampleCount == 0)
                 continue;
 
-            for (int i = 0; i < inputStreamSampleCount; i++)
+            for (int i = 0; i < inStreamSampleCount; i++)
             {
-                int inputStreamSample = inputStreamSamples[i];
-                int outputSample = outputSamples[i];
-
-                outputSamples[i]
-                    = inputStreamSample
-                            + outputSample
-                            - Math.round(
-                                    inputStreamSample
-                                        * (outputSample
-                                                / (float) maxOutputSample));
+                int inStreamSample = inStreamSamples[i];
+                int outSample = outSamples[i];
+
+                outSamples[i]
+                    = inStreamSample
+                        + outSample
+                        - Math.round(
+                                inStreamSample
+                                    * (outSample / (float) maxOutSample));
             }
         }
-        return outputSamples;
+        return outSamples;
     }
 
     /**
      * Implements {@link PushBufferStream#read(Buffer)}. If
-     * <tt>inputSamples</tt> are available, mixes them and writes the mix to the
+     * <tt>inSamples</tt> are available, mixes them and writes the mix to the
      * specified <tt>Buffer</tt> performing the necessary data type conversions.
      *
      * @param buffer the <tt>Buffer</tt> to receive the data read from this
@@ -292,77 +307,76 @@ private static int[] mix(
     public void read(Buffer buffer)
         throws IOException
     {
-        int[][] inputSamples;
-        int maxInputSampleCount;
+        int[][] inSamples;
+        int maxInSampleCount;
         long timeStamp;
 
         synchronized (readSyncRoot)
         {
-            inputSamples = this.inputSamples;
-            maxInputSampleCount = this.maxInputSampleCount;
+            inSamples = this.inSamples;
+            maxInSampleCount = this.maxInSampleCount;
             timeStamp = this.timeStamp;
 
-            this.inputSamples = null;
-            this.maxInputSampleCount = 0;
+            this.inSamples = null;
+            this.maxInSampleCount = 0;
             this.timeStamp = Buffer.TIME_UNKNOWN;
         }
 
-        int inputSampleCount = (inputSamples == null) ? 0 : inputSamples.length;
-
-        if ((inputSampleCount == 0)
-                || (maxInputSampleCount <= 0))
+        if ((inSamples == null)
+                || (inSamples.length == 0)
+                || (maxInSampleCount <= 0))
         {
-            buffer.setLength(0);
+            buffer.setDiscard(true);
             return;
         }
 
-        AudioFormat outputFormat = getFormat();
-        int[] outputSamples
-            = mix(inputSamples, outputFormat, maxInputSampleCount);
-
-        Class<?> outputDataType = outputFormat.getDataType();
+        AudioFormat outFormat = getFormat();
+        int[] outSamples = mix(inSamples, outFormat, maxInSampleCount);
+        int outSampleCount = Math.min(maxInSampleCount, outSamples.length);
 
-        if (Format.byteArray.equals(outputDataType))
+        if (Format.byteArray.equals(outFormat.getDataType()))
         {
-            byte[] outputData = null;
+            int outLength;
             Object o = buffer.getData();
+            byte[] outData = null;
+
             if (o instanceof byte[])
-                outputData = (byte[]) o;
+                outData = (byte[]) o;
 
-            switch (outputFormat.getSampleSizeInBits())
+            switch (outFormat.getSampleSizeInBits())
             {
             case 16:
-                if (outputData == null ||
-                        outputData.length < outputSamples.length * 2)
-                    outputData = new byte[outputSamples.length * 2];
-                for (int i = 0; i < outputSamples.length; i++)
-                    ArrayIOUtils.writeInt16(outputSamples[i], outputData, i * 2);
+                outLength = outSampleCount * 2;
+                if ((outData == null) || (outData.length < outLength))
+                    outData = new byte[outLength];
+                for (int i = 0; i < outSampleCount; i++)
+                    ArrayIOUtils.writeInt16(outSamples[i], outData, i * 2);
                 break;
             case 32:
-                if (outputData == null ||
-                        outputData.length < outputSamples.length * 4)
-                    outputData = new byte[outputSamples.length * 4];
-                for (int i = 0; i < outputSamples.length; i++)
-                    writeInt(outputSamples[i], outputData, i * 4);
+                outLength = outSampleCount * 4;
+                if ((outData == null) || (outData.length < outLength))
+                    outData = new byte[outLength];
+                for (int i = 0; i < outSampleCount; i++)
+                    ArrayIOUtils.writeInt(outSamples[i], outData, i * 4);
                 break;
             case 8:
             case 24:
             default:
-                throw
-                    new UnsupportedOperationException(
-                            "AudioMixingPushBufferStream.read(Buffer)");
+                throw new UnsupportedOperationException(
+                        "AudioMixingPushBufferStream.read(Buffer)");
             }
 
-            buffer.setData(outputData);
-            buffer.setFormat(outputFormat);
-            buffer.setLength(outputData.length);
+            buffer.setData(outData);
+            buffer.setFormat(outFormat);
+            buffer.setLength(outLength);
             buffer.setOffset(0);
             buffer.setTimeStamp(timeStamp);
         }
         else
-            throw
-                new UnsupportedOperationException(
-                        "AudioMixingPushBufferStream.read(Buffer)");
+        {
+            throw new UnsupportedOperationException(
+                    "AudioMixingPushBufferStream.read(Buffer)");
+        }
     }
 
     /**
@@ -370,22 +384,19 @@ public void read(Buffer buffer)
      * audio mixing by this stream when data is read from it. Triggers a push to
      * the clients of this stream.
      *
-     * @param inputSamples the collection of audio sample sets to be mixed by
+     * @param inSamples the collection of audio sample sets to be mixed by
      * this stream when data is read from it
-     * @param maxInputSampleCount the maximum number of per-stream audio samples
-     * available through <tt>inputSamples</tt>
-     * @param timeStamp the time stamp of <tt>inputSamples</tt> to be reported
+     * @param maxInSampleCount the maximum number of per-stream audio samples
+     * available through <tt>inSamples</tt>
+     * @param timeStamp the time stamp of <tt>inSamples</tt> to be reported
      * in the specified <tt>Buffer</tt> when data is read from this instance
      */
-    void setInputSamples(
-            int[][] inputSamples,
-            int maxInputSampleCount,
-            long timeStamp)
+    void setInSamples(int[][] inSamples, int maxInSampleCount, long timeStamp)
     {
         synchronized (readSyncRoot)
         {
-            this.inputSamples = inputSamples;
-            this.maxInputSampleCount = maxInputSampleCount;
+            this.inSamples = inSamples;
+            this.maxInSampleCount = maxInSampleCount;
         }
 
         BufferTransferHandler transferHandler = this.transferHandler;
@@ -417,13 +428,10 @@ public void setTransferHandler(BufferTransferHandler transferHandler)
     synchronized void start()
         throws IOException
     {
-        audioMixerStream.addOutputStream(this);
+        audioMixerStream.addOutStream(this);
         if (logger.isTraceEnabled())
-            logger
-                .trace(
-                    "Started "
-                        + getClass().getSimpleName()
-                        + " with hashCode "
+            logger.trace(
+                    "Started " + getClass().getSimpleName() + " with hashCode "
                         + hashCode());
     }
 
@@ -436,32 +444,10 @@ synchronized void start()
     synchronized void stop()
         throws IOException
     {
-        audioMixerStream.removeOutputStream(this);
+        audioMixerStream.removeOutStream(this);
         if (logger.isTraceEnabled())
-            logger
-                .trace(
-                    "Stopped "
-                        + getClass().getSimpleName()
-                        + " with hashCode "
+            logger.trace(
+                    "Stopped " + getClass().getSimpleName() + " with hashCode "
                         + hashCode());
     }
-
-    /**
-     * Converts an integer to a series of bytes and writes the result into a
-     * specific output array of bytes starting the writing at a specific offset
-     * in it.
-     *
-     * @param input the integer to be written out as a series of bytes
-     * @param output the output to receive the conversion of the specified
-     * integer to a series of bytes
-     * @param outputOffset the offset in <tt>output</tt> at which the writing of
-     * the result of the conversion is to be started
-     */
-    private static void writeInt(int input, byte[] output, int outputOffset)
-    {
-        output[outputOffset] = (byte) (input & 0xFF);
-        output[outputOffset + 1] = (byte) ((input >>> 8) & 0xFF);
-        output[outputOffset + 2] = (byte) ((input >>> 16) & 0xFF);
-        output[outputOffset + 3] = (byte) (input >> 24);
-    }
 }
diff --git a/src/org/jitsi/impl/neomedia/conference/DataSourceFilter.java b/src/org/jitsi/impl/neomedia/conference/DataSourceFilter.java
index 91609abf..a2552b24 100644
--- a/src/org/jitsi/impl/neomedia/conference/DataSourceFilter.java
+++ b/src/org/jitsi/impl/neomedia/conference/DataSourceFilter.java
@@ -12,11 +12,10 @@
  * Represents a filter which determines whether a specific <tt>DataSource</tt>
  * is to be selected or deselected by the caller of the filter.
  *
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
  */
 public interface DataSourceFilter
 {
-
     /**
      * Determines whether a specific <tt>DataSource</tt> is accepted by this
      * filter i.e. whether the caller of this filter should include it in its
diff --git a/src/org/jitsi/impl/neomedia/conference/InputDataSourceDesc.java b/src/org/jitsi/impl/neomedia/conference/InDataSourceDesc.java
similarity index 71%
rename from src/org/jitsi/impl/neomedia/conference/InputDataSourceDesc.java
rename to src/org/jitsi/impl/neomedia/conference/InDataSourceDesc.java
index af2d950b..4ebcd3d8 100644
--- a/src/org/jitsi/impl/neomedia/conference/InputDataSourceDesc.java
+++ b/src/org/jitsi/impl/neomedia/conference/InDataSourceDesc.java
@@ -26,24 +26,24 @@
  * extracted into its own file for the sake of clarity.
  * </p>
  *
- * @author Lubomir Marinov
+ * @author Lyubomir Marinov
  */
-class InputDataSourceDesc
+class InDataSourceDesc
 {
 
-    /**
-     * The <tt>Logger</tt> used by the <tt>InputDataSourceDesc</tt> class and
-     * its instances for logging output.
-     */
-    private static final Logger logger
-        = Logger.getLogger(InputDataSourceDesc.class);
-
     /**
      * The constant which represents an empty array with <tt>SourceStream</tt>
      * element type. Explicitly defined in order to avoid unnecessary allocations.
      */
     private static final SourceStream[] EMPTY_STREAMS = new SourceStream[0];
 
+    /**
+     * The <tt>Logger</tt> used by the <tt>InDataSourceDesc</tt> class and
+     * its instances for logging output.
+     */
+    private static final Logger logger
+        = Logger.getLogger(InDataSourceDesc.class);
+
     /**
      * The indicator which determines whether the effective input
      * <tt>DataSource</tt> described by this instance is currently connected.
@@ -60,41 +60,41 @@ class InputDataSourceDesc
      * The <tt>DataSource</tt> for which additional information is described by
      * this instance.
      */
-    public final DataSource inputDataSource;
+    public final DataSource inDataSource;
 
     /**
      * The <tt>AudioMixingPushBufferDataSource</tt> in which the mix
-     * contributions of {@link #inputDataSource} are to not be included.
+     * contributions of {@link #inDataSource} are to not be included.
      */
-    public final AudioMixingPushBufferDataSource outputDataSource;
+    public final AudioMixingPushBufferDataSource outDataSource;
 
     /**
      * The <tt>DataSource</tt>, if any, which transcodes the tracks of
-     * {@link #inputDataSource} in the output <tt>Format</tt> of the associated
+     * {@link #inDataSource} in the output <tt>Format</tt> of the associated
      * <tt>AudioMixer</tt>.
      */
     private DataSource transcodingDataSource;
 
     /**
-     * Initializes a new <tt>InputDataSourceDesc</tt> instance which is to
+     * Initializes a new <tt>InDataSourceDesc</tt> instance which is to
      * describe additional information about a specific input
      * <tt>DataSource</tt> of an <tt>AudioMixer</tt>. Associates the specified
      * <tt>DataSource</tt> with the <tt>AudioMixingPushBufferDataSource</tt> in
      * which the mix contributions of the specified input <tt>DataSource</tt>
      * are to not be included.
      *
-     * @param inputDataSource a <tt>DataSourc</tt> for which additional
+     * @param inDataSource a <tt>DataSourc</tt> for which additional
      * information is to be described by the new instance
-     * @param outputDataSource the <tt>AudioMixingPushBufferDataSource</tt> in
-     * which the mix contributions of <tt>inputDataSource</tt> are to not be
+     * @param outDataSource the <tt>AudioMixingPushBufferDataSource</tt> in
+     * which the mix contributions of <tt>inDataSource</tt> are to not be
      * included
      */
-    public InputDataSourceDesc(
-        DataSource inputDataSource,
-        AudioMixingPushBufferDataSource outputDataSource)
+    public InDataSourceDesc(
+            DataSource inDataSource,
+            AudioMixingPushBufferDataSource outDataSource)
     {
-        this.inputDataSource = inputDataSource;
-        this.outputDataSource = outputDataSource;
+        this.inDataSource = inDataSource;
+        this.outDataSource = outDataSource;
     }
 
     /**
@@ -103,7 +103,7 @@ public InputDataSourceDesc(
      * effective input <tt>DataSource</tt> is to be asynchronously connected,
      * the completion of the connect procedure will be reported to the specified
      * <tt>AudioMixer</tt> by calling its
-     * {@link AudioMixer#connected(InputDataSourceDesc)}.
+     * {@link AudioMixer#connected(InDataSourceDesc)}.
      *
      * @param audioMixer the <tt>AudioMixer</tt> requesting the effective input
      * <tt>DataSource</tt> described by this instance to be connected
@@ -113,12 +113,12 @@ public InputDataSourceDesc(
     synchronized void connect(final AudioMixer audioMixer)
         throws IOException
     {
-        final DataSource effectiveInputDataSource
+        final DataSource effectiveInDataSource
             = (transcodingDataSource == null)
-                ? inputDataSource
+                ? inDataSource
                 : transcodingDataSource;
 
-        if (effectiveInputDataSource instanceof TranscodingDataSource)
+        if (effectiveInDataSource instanceof TranscodingDataSource)
         {
             if (connectThread == null)
             {
@@ -129,28 +129,26 @@ public void run()
                     {
                         try
                         {
-                            audioMixer
-                                .connect(
-                                    effectiveInputDataSource,
-                                    inputDataSource);
-                            synchronized (InputDataSourceDesc.this)
+                            audioMixer.connect(
+                                    effectiveInDataSource,
+                                    inDataSource);
+                            synchronized (InDataSourceDesc.this)
                             {
                                 connected = true;
                             }
-                            audioMixer.connected(InputDataSourceDesc.this);
+                            audioMixer.connected(InDataSourceDesc.this);
                         }
                         catch (IOException ioex)
                         {
-                            logger
-                                .error(
-                                    "Failed to connect to inputDataSource "
-                                        + MediaStreamImpl
-                                            .toString(inputDataSource),
+                            logger.error(
+                                    "Failed to connect to inDataSource "
+                                        + MediaStreamImpl.toString(
+                                                inDataSource),
                                     ioex);
                         }
                         finally
                         {
-                            synchronized (InputDataSourceDesc.this)
+                            synchronized (InDataSourceDesc.this)
                             {
                                 if (connectThread == Thread.currentThread())
                                     connectThread = null;
@@ -164,7 +162,7 @@ public void run()
         }
         else
         {
-            audioMixer.connect(effectiveInputDataSource, inputDataSource);
+            audioMixer.connect(effectiveInDataSource, inDataSource);
             connected = true;
         }
     }
@@ -174,18 +172,18 @@ public void run()
      * the input <tt>DataSource</tt> described by this instance into a specific
      * output <tt>Format</tt>.
      *
-     * @param outputFormat the <tt>Format</tt> in which the tracks of the input
+     * @param outFormat the <tt>Format</tt> in which the tracks of the input
      * <tt>DataSource</tt> described by this instance are to be transcoded
      * @return <tt>true</tt> if a new transcoding <tt>DataSource</tt> has been
      * created for the input <tt>DataSource</tt> described by this instance;
      * otherwise, <tt>false</tt>
      */
-    synchronized boolean createTranscodingDataSource(Format outputFormat)
+    synchronized boolean createTranscodingDataSource(Format outFormat)
     {
         if (transcodingDataSource == null)
         {
             setTranscodingDataSource(
-                new TranscodingDataSource(inputDataSource, outputFormat));
+                    new TranscodingDataSource(inDataSource, outFormat));
             return true;
         }
         else
@@ -200,7 +198,7 @@ synchronized void disconnect()
     {
         if (connected)
         {
-            getEffectiveInputDataSource().disconnect();
+            getEffectiveInDataSource().disconnect();
             connected = false;
         }
     }
@@ -218,12 +216,12 @@ synchronized void disconnect()
      */
     public synchronized Object getControl(String controlType)
     {
-        DataSource effectiveInputDataSource = getEffectiveInputDataSource();
+        DataSource effectiveInDataSource = getEffectiveInDataSource();
 
         return
-            (effectiveInputDataSource == null)
+            (effectiveInDataSource == null)
                 ? null
-                : effectiveInputDataSource.getControl(controlType);
+                : effectiveInDataSource.getControl(controlType);
     }
 
     /**
@@ -235,14 +233,24 @@ public synchronized Object getControl(String controlType)
      * <tt>AudioMixer</tt> directly reads in order to retrieve the mix
      * contribution of the <tt>DataSource</tt> described by this instance
      */
-    public synchronized DataSource getEffectiveInputDataSource()
+    public synchronized DataSource getEffectiveInDataSource()
     {
         return
             (transcodingDataSource == null)
-                ? inputDataSource
+                ? inDataSource
                 : (connected ? transcodingDataSource : null);
     }
 
+    /**
+     * Returns this instance's <tt>inDataSource</tt>
+     *
+     * @return this instance's <tt>inDataSource</tt>
+     */
+    public DataSource getInDataSource()
+    {
+        return inDataSource;
+    }
+
     /**
      * Gets the <tt>SourceStream</tt>s of the effective input
      * <tt>DataSource</tt> described by this instance.
@@ -255,18 +263,31 @@ public synchronized SourceStream[] getStreams()
         if (!connected)
             return EMPTY_STREAMS;
 
-        DataSource inputDataSource = getEffectiveInputDataSource();
+        DataSource inDataSource = getEffectiveInDataSource();
 
-        if (inputDataSource instanceof PushBufferDataSource)
-            return ((PushBufferDataSource) inputDataSource).getStreams();
-        else if (inputDataSource instanceof PullBufferDataSource)
-            return ((PullBufferDataSource) inputDataSource).getStreams();
-        else if (inputDataSource instanceof TranscodingDataSource)
-            return ((TranscodingDataSource) inputDataSource).getStreams();
+        if (inDataSource instanceof PushBufferDataSource)
+            return ((PushBufferDataSource) inDataSource).getStreams();
+        else if (inDataSource instanceof PullBufferDataSource)
+            return ((PullBufferDataSource) inDataSource).getStreams();
+        else if (inDataSource instanceof TranscodingDataSource)
+            return ((TranscodingDataSource) inDataSource).getStreams();
         else
             return null;
     }
 
+    /**
+     * Returns the <tt>TranscodingDataSource</tt> object used in this instance.
+     *
+     * @return the <tt>TranscodingDataSource</tt> object used in this instance.
+     */
+    public TranscodingDataSource getTranscodingDataSource()
+    {
+        return
+            (transcodingDataSource == null)
+                ? null
+                : (TranscodingDataSource) transcodingDataSource;
+    }
+
     /**
      * Sets the <tt>DataSource</tt>, if any, which transcodes the tracks of the
      * input <tt>DataSource</tt> described by this instance in the output
@@ -294,7 +315,7 @@ synchronized void start()
         throws IOException
     {
         if (connected)
-            getEffectiveInputDataSource().start();
+            getEffectiveInDataSource().start();
     }
 
     /**
@@ -308,28 +329,6 @@ synchronized void stop()
         throws IOException
     {
         if (connected)
-            getEffectiveInputDataSource().stop();
-    }
-
-    /**
-     * Returns this instance's <tt>inputDataSource</tt>
-     *
-     * @return this instance's <tt>inputDataSource</tt>
-     */
-    public DataSource getInputDataSource()
-    {
-        return inputDataSource;
-    }
-
-    /**
-     * Returns the <tt>TranscodingDataSource</tt> object used in this instance.
-     *
-     * @return the <tt>TranscodingDataSource</tt> object used in this instance.
-     */
-    public TranscodingDataSource getTranscodingDataSource()
-    {
-        return (transcodingDataSource == null)?
-                null
-                : (TranscodingDataSource) transcodingDataSource;
+            getEffectiveInDataSource().stop();
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/conference/InputStreamDesc.java b/src/org/jitsi/impl/neomedia/conference/InStreamDesc.java
similarity index 78%
rename from src/org/jitsi/impl/neomedia/conference/InputStreamDesc.java
rename to src/org/jitsi/impl/neomedia/conference/InStreamDesc.java
index 5cfacbb2..f2f43448 100644
--- a/src/org/jitsi/impl/neomedia/conference/InputStreamDesc.java
+++ b/src/org/jitsi/impl/neomedia/conference/InStreamDesc.java
@@ -24,11 +24,11 @@
  *
  * @author Lyubomir Marinov
  */
-class InputStreamDesc
+class InStreamDesc
 {
     /**
      * The <tt>Buffer</tt> into which media data is to be read from
-     * {@link #inputStream}.
+     * {@link #inStream}.
      */
     private SoftReference<Buffer> buffer;
 
@@ -36,13 +36,13 @@ class InputStreamDesc
      * The <tt>DataSource</tt> which created the <tt>SourceStream</tt> described
      * by this instance and additional information about it.
      */
-    public final InputDataSourceDesc inputDataSourceDesc;
+    public final InDataSourceDesc inDataSourceDesc;
 
     /**
      * The <tt>SourceStream</tt> for which additional information is described
      * by this instance.
      */
-    private SourceStream inputStream;
+    private SourceStream inStream;
 
     /**
      * The number of reads of this input stream which did not return any
@@ -51,24 +51,24 @@ class InputStreamDesc
     long nonContributingReadCount;
 
     /**
-     * Initializes a new <tt>InputStreamDesc</tt> instance which is to describe
+     * Initializes a new <tt>InStreamDesc</tt> instance which is to describe
      * additional information about a specific input audio <tt>SourceStream</tt>
      * of an <tt>AudioMixer</tt>. Associates the specified <tt>SourceStream</tt>
      * with the <tt>DataSource</tt> which created it and additional information
      * about it.
      *
-     * @param inputStream a <tt>SourceStream</tt> for which additional
+     * @param inStream a <tt>SourceStream</tt> for which additional
      * information is to be described by the new instance
-     * @param inputDataSourceDesc the <tt>DataSource</tt> which created the
+     * @param inDataSourceDesc the <tt>DataSource</tt> which created the
      * <tt>SourceStream</tt> to be described by the new instance and additional
      * information about it
      */
-    public InputStreamDesc(
-        SourceStream inputStream,
-        InputDataSourceDesc inputDataSourceDesc)
+    public InStreamDesc(
+            SourceStream inStream,
+            InDataSourceDesc inDataSourceDesc)
     {
-        this.inputStream = inputStream;
-        this.inputDataSourceDesc = inputDataSourceDesc;
+        this.inStream = inStream;
+        this.inDataSourceDesc = inDataSourceDesc;
     }
 
     /**
@@ -97,9 +97,9 @@ public Buffer getBuffer(boolean create)
      *
      * @return the <tt>SourceStream</tt> described by this instance
      */
-    public SourceStream getInputStream()
+    public SourceStream getInStream()
     {
-        return inputStream;
+        return inStream;
     }
 
     /**
@@ -111,9 +111,9 @@ public SourceStream getInputStream()
      * contribution of the <tt>SourceStream</tt> described by this instance is
      * to not be included
      */
-    public AudioMixingPushBufferDataSource getOutputDataSource()
+    public AudioMixingPushBufferDataSource getOutDataSource()
     {
-        return inputDataSourceDesc.outputDataSource;
+        return inDataSourceDesc.outDataSource;
     }
 
     /**
@@ -132,17 +132,17 @@ public void setBuffer(Buffer buffer)
     /**
      * Sets the <tt>SourceStream</tt> to be described by this instance.
      *
-     * @param inputStream the <tt>SourceStream</tt> to be described by this
+     * @param inStream the <tt>SourceStream</tt> to be described by this
      * instance
      */
-    public void setInputStream(SourceStream inputStream)
+    public void setInStream(SourceStream inStream)
     {
-        if (this.inputStream != inputStream)
+        if (this.inStream != inStream)
         {
-            this.inputStream = inputStream;
+            this.inStream = inStream;
 
             /*
-             * Since the inputStream has changed, one may argue that the Buffer
+             * Since the inStream has changed, one may argue that the Buffer
              * of the old value is not optimal for the new value.
              */
             setBuffer(null);
diff --git a/src/org/jitsi/impl/neomedia/conference/IntArrayCache.java b/src/org/jitsi/impl/neomedia/conference/IntArrayCache.java
new file mode 100644
index 00000000..63a10759
--- /dev/null
+++ b/src/org/jitsi/impl/neomedia/conference/IntArrayCache.java
@@ -0,0 +1,96 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jitsi.impl.neomedia.conference;
+
+import java.lang.ref.*;
+import java.util.*;
+
+import javax.media.*;
+
+/**
+ * Caches <tt>int</tt> arrays for the purposes of reducing garbage collection.
+ *
+ * @author Lyubomir Marinov
+ */
+class IntArrayCache
+{
+    /**
+     * The cache of <tt>int</tt> arrays managed by this instance for the
+     * purposes of reducing garbage collection.
+     */
+    private SoftReference<List<int[]>> intArrays;
+
+    public synchronized int[] allocateIntArray(int minSize)
+    {
+        List<int[]> intArrays
+            = (this.intArrays == null) ? null : this.intArrays.get();
+
+        if (intArrays != null)
+        {
+            Iterator<int[]> i = intArrays.iterator();
+
+            while (i.hasNext())
+            {
+                int[] intArray = i.next();
+
+                if (intArray.length >= minSize)
+                {
+                    i.remove();
+                    return intArray;
+                }
+            }
+        }
+
+        return new int[minSize];
+    }
+
+    public synchronized void deallocateIntArray(int[] intArray)
+    {
+        if (intArray == null)
+            return;
+
+        List<int[]> intArrays;
+
+        if ((this.intArrays == null)
+                || ((intArrays = this.intArrays.get()) == null))
+        {
+            intArrays = new LinkedList<int[]>();
+            this.intArrays = new SoftReference<List<int[]>>(intArrays);
+        }
+
+        if (intArrays.size() != 0)
+            for (int[] element : intArrays)
+                if (element == intArray)
+                    return;
+
+        intArrays.add(intArray);
+    }
+
+    public int[] validateIntArraySize(Buffer buffer, int newSize)
+    {
+        Object data = buffer.getData();
+        int[] intArray;
+
+        if (data instanceof int[])
+        {
+            intArray = (int[]) data;
+            if (intArray.length < newSize)
+            {
+                deallocateIntArray(intArray);
+                intArray = null;
+            }
+        }
+        else
+            intArray = null;
+        if (intArray == null)
+        {
+            intArray = allocateIntArray(newSize);
+            buffer.setData(intArray);
+        }
+        return intArray;
+    }
+}
diff --git a/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceImpl.java b/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceImpl.java
index 15b606e3..051367ff 100644
--- a/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceImpl.java
+++ b/src/org/jitsi/impl/neomedia/device/AudioMediaDeviceImpl.java
@@ -146,14 +146,14 @@ protected synchronized CaptureDevice createCaptureDevice()
                         captureDeviceSharing
                             = createCaptureDeviceSharing(captureDevice);
                         captureDevice
-                            = captureDeviceSharing.createOutputDataSource();
+                            = captureDeviceSharing.createOutDataSource();
                     }
                 }
                 if ((captureDevice == null) && createCaptureDeviceIfNull)
                     captureDevice = superCreateCaptureDevice();
             }
             else
-                captureDevice = captureDeviceSharing.createOutputDataSource();
+                captureDevice = captureDeviceSharing.createOutDataSource();
         }
         return captureDevice;
     }
diff --git a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
index 31549f8c..75d10a42 100644
--- a/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
+++ b/src/org/jitsi/impl/neomedia/device/AudioMixerMediaDevice.java
@@ -203,7 +203,7 @@ public void connect(DataSource captureDevice)
     @Override
     public AudioMixingPushBufferDataSource createOutputDataSource()
     {
-        return getAudioMixer().createOutputDataSource();
+        return getAudioMixer().createOutDataSource();
     }
 
     /**
@@ -513,7 +513,7 @@ void removeInputDataSources(DataSourceFilter dataSourceFilter)
         AudioMixer audioMixer = this.audioMixer;
 
         if (audioMixer != null)
-            audioMixer.removeInputDataSources(dataSourceFilter);
+            audioMixer.removeInDataSources(dataSourceFilter);
     }
 
     /**
@@ -673,7 +673,7 @@ public void addReceiveStream(ReceiveStream receiveStream)
         @Override
         protected DataSource createCaptureDevice()
         {
-            return getAudioMixer().getLocalOutputDataSource();
+            return getAudioMixer().getLocalOutDataSource();
         }
 
         /**
@@ -1044,7 +1044,7 @@ protected void playbackDataSourceAdded(DataSource playbackDataSource)
                         .getDataSource();
             if (captureDevice instanceof AudioMixingPushBufferDataSource)
                 ((AudioMixingPushBufferDataSource) captureDevice)
-                    .addInputDataSource(playbackDataSource);
+                    .addInDataSource(playbackDataSource);
 
             audioMixerMediaDeviceSession.addPlaybackDataSource(
                     playbackDataSource);
@@ -1094,7 +1094,7 @@ protected void playbackDataSourceUpdated(DataSource playbackDataSource)
             if (captureDevice instanceof AudioMixingPushBufferDataSource)
             {
                 ((AudioMixingPushBufferDataSource) captureDevice)
-                    .updateInputDataSource(playbackDataSource);
+                    .updateInDataSource(playbackDataSource);
             }
         }
 
diff --git a/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java b/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java
index 4453a4e4..8edf7c74 100644
--- a/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java
+++ b/src/org/jitsi/impl/neomedia/device/MediaDeviceSession.java
@@ -1808,9 +1808,7 @@ public void addDTMF(DTMFInbandTone tone)
         DataSource captureDevice = this.captureDevice;
 
         if (captureDevice instanceof InbandDTMFDataSource)
-        {
             ((InbandDTMFDataSource) captureDevice).addDTMF(tone);
-        }
     }
 
     /**
diff --git a/src/org/jitsi/service/neomedia/DTMFInbandTone.java b/src/org/jitsi/service/neomedia/DTMFInbandTone.java
index 5d85db56..5475c0d2 100644
--- a/src/org/jitsi/service/neomedia/DTMFInbandTone.java
+++ b/src/org/jitsi/service/neomedia/DTMFInbandTone.java
@@ -6,6 +6,8 @@
  */
 package org.jitsi.service.neomedia;
 
+import org.jitsi.service.protocol.*;
+
 /**
  * Manages the generation of the inband DMTF signal. A signal is identified by a
  * value (1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, A, B, C and D) and each signal is
@@ -28,154 +30,148 @@ public class DTMFInbandTone
     /**
      * The first set of frequencies in Hz which composes an inband DTMF.
      */
-    private static final double[] frequencyList1 =
-    new double[]
-    {
-        697.0, 770.0, 852.0, 941.0
-    };
+    private static final double[] FREQUENCY_LIST_1
+        = new double[] { 697.0, 770.0, 852.0, 941.0 };
 
     /**
      * The second set of frequencies in Hz which composes an inband DTMF.
      */
-    private static final double[] frequencyList2 =
-    new double[]
-    {
-        1209.0, 1336.0, 1477.0, 1633.0
-    };
+    private static final double[] FREQUENCY_LIST_2
+        = new double[] { 1209.0, 1336.0, 1477.0, 1633.0 };
 
     /**
      * The "0" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_0 = new DTMFInbandTone("0",
-            frequencyList1[3],
-            frequencyList2[1]);
+            FREQUENCY_LIST_1[3],
+            FREQUENCY_LIST_2[1]);
 
     /**
      * The "1" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_1 = new DTMFInbandTone("1",
-            frequencyList1[0],
-            frequencyList2[0]);
+            FREQUENCY_LIST_1[0],
+            FREQUENCY_LIST_2[0]);
 
     /**
      * The "2" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_2 = new DTMFInbandTone("2",
-            frequencyList1[0],
-            frequencyList2[1]);
+            FREQUENCY_LIST_1[0],
+            FREQUENCY_LIST_2[1]);
 
     /**
      * The "3" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_3 = new DTMFInbandTone("3",
-            frequencyList1[0],
-            frequencyList2[2]);
+            FREQUENCY_LIST_1[0],
+            FREQUENCY_LIST_2[2]);
 
     /**
      * The "4" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_4 = new DTMFInbandTone("4",
-            frequencyList1[1],
-            frequencyList2[0]);
+            FREQUENCY_LIST_1[1],
+            FREQUENCY_LIST_2[0]);
 
     /**
      * The "5" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_5 = new DTMFInbandTone("5",
-            frequencyList1[1],
-            frequencyList2[1]);
+            FREQUENCY_LIST_1[1],
+            FREQUENCY_LIST_2[1]);
 
     /**
      * The "6" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_6 = new DTMFInbandTone("6",
-            frequencyList1[1],
-            frequencyList2[2]);
+            FREQUENCY_LIST_1[1],
+            FREQUENCY_LIST_2[2]);
 
     /**
      * The "7" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_7 = new DTMFInbandTone("7",
-            frequencyList1[2],
-            frequencyList2[0]);
+            FREQUENCY_LIST_1[2],
+            FREQUENCY_LIST_2[0]);
 
     /**
      * The "8" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_8 = new DTMFInbandTone("8",
-            frequencyList1[2],
-            frequencyList2[1]);
+            FREQUENCY_LIST_1[2],
+            FREQUENCY_LIST_2[1]);
 
     /**
      * The "9" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_9 = new DTMFInbandTone("9",
-            frequencyList1[2],
-            frequencyList2[2]);
+            FREQUENCY_LIST_1[2],
+            FREQUENCY_LIST_2[2]);
 
     /**
      * The "*" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_STAR =
         new DTMFInbandTone("*",
-            frequencyList1[3],
-            frequencyList2[0]);
+            FREQUENCY_LIST_1[3],
+            FREQUENCY_LIST_2[0]);
 
     /**
      * The "#" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_SHARP =
         new DTMFInbandTone("#",
-            frequencyList1[3],
-            frequencyList2[2]);
+            FREQUENCY_LIST_1[3],
+            FREQUENCY_LIST_2[2]);
 
     /**
      * The "A" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_A = new DTMFInbandTone("A",
-            frequencyList1[0],
-            frequencyList2[3]);
+            FREQUENCY_LIST_1[0],
+            FREQUENCY_LIST_2[3]);
 
     /**
      * The "B" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_B = new DTMFInbandTone("B",
-            frequencyList1[1],
-            frequencyList2[3]);
+            FREQUENCY_LIST_1[1],
+            FREQUENCY_LIST_2[3]);
 
     /**
      * The "C" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_C = new DTMFInbandTone("C",
-            frequencyList1[2],
-            frequencyList2[3]);
+            FREQUENCY_LIST_1[2],
+            FREQUENCY_LIST_2[3]);
 
     /**
      * The "D" DTMF Inband Tone.
      */
     public static final DTMFInbandTone DTMF_INBAND_D = new DTMFInbandTone("D",
-            frequencyList1[3],
-            frequencyList2[3]);
+            FREQUENCY_LIST_1[3],
+            FREQUENCY_LIST_2[3]);
 
     /**
      * The default duration of an inband DTMF tone in ms.
      * 50 ms c.f.
      * http://nemesis.lonestar.org/reference/telecom/signaling/dtmf.html
-     * which cites the norm ANSI T1.401-1988 (but unavailable to me).
-     * But when testing it at 50 ms, the asterisk servers miss some DTMF tone
-     * impulses. Thus, set it up 150 ms.
+     * which cites the norm ANSI T1.401-1988.
+     * But when testing it at 50 ms, the Asterisk servers miss some DTMF tone
+     * impulses. Thus, set up to 150 ms.
      */
-    private static final int toneDuration = 150;
+    private static final int TONE_DURATION = 150;
 
     /**
      * The default duration of an inband DTMF tone in ms.
      * 45 ms c.f.
      * http://nemesis.lonestar.org/reference/telecom/signaling/dtmf.html
-     * which cites the norm ANSI T1.401-1988 (but unavailable to me).
-     * Moreover the minimum duty cycle (signal tone + silence) for
+     * which cites the norm ANSI T1.401-1988.
+     * Moreover, the minimum duty cycle (signal tone + silence) for
      * ANSI-compliance shall be greater or equal to 100 ms.
      */
-    private static final int interDigitInterval = 45;
+    private static final int INTER_DIGIT_INTERVAL = 45;
 
     /**
      * The value which identifies the current inband tone. Available values are
@@ -314,48 +310,46 @@ public int getAudioSampleDiscrete(
      * Generates a signal sample for the current tone signal and stores it into
      * the byte data array.
      *
-     * @param samplingFrequency The sampling frequency (codec clock rate) in Hz
-     * of the stream which will encapsulate this signal.
+     * @param sampleRate The sampling frequency (codec clock rate) in Hz of the
+     * stream which will encapsulate this signal.
      * @param sampleSizeInBits The size of each sample (8 for a byte, 16 for a
      * short and 32 for an int)
-     *
      * @return The data array containing the DTMF signal.
      */
-    public int[] getAudioSamples(
-            double samplingFrequency,
-            int sampleSizeInBits)
+    public int[] getAudioSamples(double sampleRate, int sampleSizeInBits)
     {
-        int sampleNumber = 0;
-
-        int nbToneSamples = ((int) (samplingFrequency / 1000.0)) *
-            DTMFInbandTone.toneDuration;
-        int nbInterDigitSamples = ((int) (samplingFrequency / 1000.0)) *
-            DTMFInbandTone.interDigitInterval;
-
-        int[] sampleData =
-            new int[nbInterDigitSamples + nbToneSamples + nbInterDigitSamples];
-
-        while(sampleNumber < nbInterDigitSamples)
-        {
-            sampleData[sampleNumber] = 0;
-            ++sampleNumber;
-        }
-        while(sampleNumber < nbInterDigitSamples + nbToneSamples)
+        /*
+         * TODO Rounding the sampleRate to an integer so early will lead to a
+         * very inaccurate or at least not quite expected number of samples.
+         */
+        int kHz = (int) (sampleRate / 1000.0);
+        int nbToneSamples = kHz * DTMFInbandTone.TONE_DURATION;
+        int nbInterDigitSamples = kHz * DTMFInbandTone.INTER_DIGIT_INTERVAL;
+
+        int[] samples
+            = new int[nbInterDigitSamples + nbToneSamples + nbInterDigitSamples];
+
+        /*
+         * The leading nbInterDigitSamples should be zeroes. They are because we
+         * have just allocated the array.
+         */
+        for (int sampleNumber = nbInterDigitSamples,
+                    endSampleNumber = nbInterDigitSamples + nbToneSamples;
+                sampleNumber < endSampleNumber;
+                sampleNumber++)
         {
-            sampleData[sampleNumber] = getAudioSampleDiscrete(
-                    samplingFrequency,
-                    sampleNumber,
-                    sampleSizeInBits);
-
-            ++sampleNumber;
-        }
-        while(sampleNumber < sampleData.length)
-        {
-            sampleData[sampleNumber] = 0;
-            ++sampleNumber;
+            samples[sampleNumber]
+                = getAudioSampleDiscrete(
+                        sampleRate,
+                        sampleNumber,
+                        sampleSizeInBits);
         }
+        /*
+         * The trailing nbInterDigitSamples should be zeroes. They are because
+         * we have just allocated the array.
+         */
 
-        return sampleData;
+        return samples;
     }
 
     /**
@@ -366,58 +360,41 @@ public int[] getAudioSamples(
      * @return the corresponding DTMF tone which contains a value as an
      * identifier and two frequencies composing the inband tone.
      */
-    public static DTMFInbandTone
-        mapTone(org.jitsi.service.protocol.DTMFTone tone)
+    public static DTMFInbandTone mapTone(DTMFTone tone)
     {
-        if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_0))
+        if(tone.equals(DTMFTone.DTMF_0))
             return DTMFInbandTone.DTMF_INBAND_0;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_1))
+        else if(tone.equals(DTMFTone.DTMF_1))
             return DTMFInbandTone.DTMF_INBAND_1;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_2))
+        else if(tone.equals(DTMFTone.DTMF_2))
             return DTMFInbandTone.DTMF_INBAND_2;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_3))
+        else if(tone.equals(DTMFTone.DTMF_3))
             return DTMFInbandTone.DTMF_INBAND_3;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_4))
+        else if(tone.equals(DTMFTone.DTMF_4))
             return DTMFInbandTone.DTMF_INBAND_4;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_5))
+        else if(tone.equals(DTMFTone.DTMF_5))
             return DTMFInbandTone.DTMF_INBAND_5;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_6))
+        else if(tone.equals(DTMFTone.DTMF_6))
             return DTMFInbandTone.DTMF_INBAND_6;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_7))
+        else if(tone.equals(DTMFTone.DTMF_7))
             return DTMFInbandTone.DTMF_INBAND_7;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_8))
+        else if(tone.equals(DTMFTone.DTMF_8))
             return DTMFInbandTone.DTMF_INBAND_8;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_9))
+        else if(tone.equals(DTMFTone.DTMF_9))
             return DTMFInbandTone.DTMF_INBAND_9;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_A))
+        else if(tone.equals(DTMFTone.DTMF_A))
             return DTMFInbandTone.DTMF_INBAND_A;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_B))
+        else if(tone.equals(DTMFTone.DTMF_B))
             return DTMFInbandTone.DTMF_INBAND_B;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_C))
+        else if(tone.equals(DTMFTone.DTMF_C))
             return DTMFInbandTone.DTMF_INBAND_C;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_D))
+        else if(tone.equals(DTMFTone.DTMF_D))
             return DTMFInbandTone.DTMF_INBAND_D;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_SHARP))
+        else if(tone.equals(DTMFTone.DTMF_SHARP))
             return DTMFInbandTone.DTMF_INBAND_SHARP;
-        else if(tone.equals(
-            org.jitsi.service.protocol.DTMFTone.DTMF_STAR))
+        else if(tone.equals(DTMFTone.DTMF_STAR))
             return DTMFInbandTone.DTMF_INBAND_STAR;
-
-        return null;
+        else
+            return null;
     }
 }
-- 
GitLab