From ec4e13012fc0d2e39a8c67e153f1a98b91b1fd04 Mon Sep 17 00:00:00 2001
From: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Wed, 2 Apr 2014 23:24:03 +0300
Subject: [PATCH] Removes duplication.

---
 .../neomedia/device/MacCoreaudioSystem.java   | 530 ++----------------
 .../impl/neomedia/device/PortAudioSystem.java | 472 +---------------
 .../maccoreaudio/MacCoreaudioStream.java      | 230 ++++----
 .../protocol/portaudio/PortAudioStream.java   |  78 ++-
 .../renderer/audio/MacCoreaudioRenderer.java  | 122 ++--
 .../renderer/audio/PortAudioRenderer.java     |  21 +-
 .../protocol/PushBufferDataSourceAdapter.java |  12 +-
 7 files changed, 309 insertions(+), 1156 deletions(-)

diff --git a/src/org/jitsi/impl/neomedia/device/MacCoreaudioSystem.java b/src/org/jitsi/impl/neomedia/device/MacCoreaudioSystem.java
index 62aacf4d..204b5f5d 100644
--- a/src/org/jitsi/impl/neomedia/device/MacCoreaudioSystem.java
+++ b/src/org/jitsi/impl/neomedia/device/MacCoreaudioSystem.java
@@ -6,17 +6,13 @@
  */
 package org.jitsi.impl.neomedia.device;
 
-import java.lang.ref.*;
 import java.util.*;
-import java.util.regex.*;
 
 import javax.media.*;
 import javax.media.format.*;
 
 import org.jitsi.impl.neomedia.*;
 import org.jitsi.impl.neomedia.jmfext.media.renderer.audio.*;
-import org.jitsi.service.configuration.*;
-import org.jitsi.service.libjitsi.*;
 import org.jitsi.util.*;
 
 /**
@@ -26,42 +22,11 @@
  * @author Vincent Lucas
  */
 public class MacCoreaudioSystem
-    extends AudioSystem
+    extends AudioSystem2
 {
-    /**
-     * Represents a listener which is to be notified before and after
-     * MacCoreaudio's native function <tt>UpdateAvailableDeviceList()</tt> is
-     * invoked.
-     */
-    public interface UpdateAvailableDeviceListListener
-        extends EventListener
-    {
-        /**
-         * Notifies this listener that MacCoreaudio's native function
-         * <tt>UpdateAvailableDeviceList()</tt> was invoked.
-         *
-         * @throws Exception if this implementation encounters an error. Any
-         * <tt>Throwable</tt> apart from <tt>ThreadDeath</tt> will be ignored
-         * after it is logged for debugging purposes.
-         */
-        void didUpdateAvailableDeviceList()
-            throws Exception;
-
-        /**
-         * Notifies this listener that MacCoreaudio's native function
-         * <tt>UpdateAvailableDeviceList()</tt> will be invoked.
-         *
-         * @throws Exception if this implementation encounters an error. Any
-         * <tt>Throwable</tt> apart from <tt>ThreadDeath</tt> will be ignored
-         * after it is logged for debugging purposes.
-         */
-        void willUpdateAvailableDeviceList()
-            throws Exception;
-    }
-
     /**
      * The protocol of the <tt>MediaLocator</tt>s identifying MacCoreaudio
-     * <tt>CaptureDevice</tt>s
+     * <tt>CaptureDevice</tt>s.
      */
     private static final String LOCATOR_PROTOCOL
         = LOCATOR_PROTOCOL_MACCOREAUDIO;
@@ -73,183 +38,6 @@ void willUpdateAvailableDeviceList()
     private static final Logger logger
         = Logger.getLogger(MacCoreaudioSystem.class);
 
-    /**
-     * The number of times that {@link #willPaOpenStream()} has been
-     * invoked without an intervening {@link #didPaOpenStream()} i.e. the
-     * number of MacCoreaudio clients which are currently executing
-     * <tt>Pa_OpenStream</tt> and which are thus inhibiting
-     * <tt>Pa_UpdateAvailableDeviceList</tt>.
-     */
-    private static int openStream = 0;
-
-    /**
-     * The <tt>Object</tt> which synchronizes that access to
-     * {@link #paOpenStream} and {@link #updateAvailableDeviceList}.
-     */
-    private static final Object openStreamSyncRoot = new Object();
-
-    /**
-     * The number of times that {@link #willPaUpdateAvailableDeviceList()}
-     * has been invoked without an intervening
-     * {@link #didPaUpdateAvailableDeviceList()} i.e. the number of
-     * MacCoreaudio clients which are currently executing
-     * <tt>Pa_UpdateAvailableDeviceList</tt> and which are thus inhibiting
-     * <tt>Pa_OpenStream</tt>.
-     */
-    private static int updateAvailableDeviceList = 0;
-
-    /**
-     * The list of <tt>PaUpdateAvailableDeviceListListener</tt>s which are to be
-     * notified before and after MacCoreaudio's native function
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> is invoked.
-     */
-    private static final List<WeakReference<UpdateAvailableDeviceListListener>>
-        updateAvailableDeviceListListeners
-        = new LinkedList<WeakReference<UpdateAvailableDeviceListListener>>();
-
-    /**
-     * The <tt>Object</tt> which ensures that MacCoreaudio's native function
-     * <tt>UpdateAvailableDeviceList()</tt> will not be invoked concurrently.
-     * The condition should hold true on the native side but, anyway, it shoul
-     * not hurt (much) to enforce it on the Java side as well.
-     */
-    private static final Object updateAvailableDeviceListSyncRoot
-        = new Object();
-
-    /**
-     * Adds a listener which is to be notified before and after MacCoreaudio's
-     * native function <tt>UpdateAvailableDeviceList()</tt> is invoked.
-     * <p>
-     * <b>Note</b>: The <tt>MacCoreaudioSystem</tt> class keeps a
-     * <tt>WeakReference</tt> to the specified <tt>listener</tt> in order to
-     * avoid memory leaks.
-     * </p>
-     *
-     * @param listener the <tt>UpdateAvailableDeviceListListener</tt> to be
-     * notified before and after MacCoreaudio's native function
-     * <tt>UpdateAvailableDeviceList()</tt> is invoked
-     */
-    public static void addUpdateAvailableDeviceListListener(
-            UpdateAvailableDeviceListListener listener)
-    {
-        if(listener == null)
-            throw new NullPointerException("listener");
-
-        synchronized(updateAvailableDeviceListListeners)
-        {
-            Iterator<WeakReference<UpdateAvailableDeviceListListener>> i
-                = updateAvailableDeviceListListeners.iterator();
-            boolean add = true;
-
-            while(i.hasNext())
-            {
-                UpdateAvailableDeviceListListener l = i.next().get();
-
-                if(l == null)
-                    i.remove();
-                else if(l.equals(listener))
-                    add = false;
-            }
-            if(add)
-            {
-                updateAvailableDeviceListListeners.add(
-                        new WeakReference<UpdateAvailableDeviceListListener>(
-                                listener));
-            }
-        }
-    }
-
-    /**
-     * Notifies <tt>MacCoreaudioSystem</tt> that a MacCoreaudio client finished
-     * executing <tt>OpenStream</tt>.
-     */
-    public static void didOpenStream()
-    {
-        synchronized (openStreamSyncRoot)
-        {
-            openStream--;
-            if (openStream < 0)
-                openStream = 0;
-
-            openStreamSyncRoot.notifyAll();
-        }
-    }
-
-    /**
-     * Notifies <tt>MacCoreaudioSystem</tt> that a MacCoreaudio client finished
-     * executing <tt>UpdateAvailableDeviceList</tt>.
-     */
-    private static void didUpdateAvailableDeviceList()
-    {
-        synchronized(openStreamSyncRoot)
-        {
-            updateAvailableDeviceList--;
-            if (updateAvailableDeviceList < 0)
-                updateAvailableDeviceList = 0;
-
-            openStreamSyncRoot.notifyAll();
-        }
-
-        fireUpdateAvailableDeviceListEvent(false);
-    }
-
-    /**
-     * Notifies the registered <tt>UpdateAvailableDeviceListListener</tt>s
-     * that MacCoreaudio's native function
-     * <tt>UpdateAvailableDeviceList()</tt> will be or was invoked.
-     *
-     * @param will <tt>true</tt> if MacCoreaudio's native function
-     * <tt>UpdateAvailableDeviceList()</tt> will be invoked or <tt>false</tt>
-     * if it was invoked
-     */
-    private static void fireUpdateAvailableDeviceListEvent(boolean will)
-    {
-        try
-        {
-            List<WeakReference<UpdateAvailableDeviceListListener>> ls;
-
-            synchronized(updateAvailableDeviceListListeners)
-            {
-                ls = new
-                    ArrayList<WeakReference<UpdateAvailableDeviceListListener>>(
-                            updateAvailableDeviceListListeners);
-            }
-
-            for(WeakReference<UpdateAvailableDeviceListListener> wr : ls)
-            {
-                UpdateAvailableDeviceListListener l = wr.get();
-                if(l != null)
-                {
-                    try
-                    {
-                        if(will)
-                            l.willUpdateAvailableDeviceList();
-                        else
-                            l.didUpdateAvailableDeviceList();
-                    }
-                    catch (Throwable t)
-                    {
-                        if(t instanceof ThreadDeath)
-                            throw(ThreadDeath) t;
-                        else
-                        {
-                            logger.error(
-                                    "UpdateAvailableDeviceListListener."
-                                    + (will ? "will" : "did")
-                                    + "UpdateAvailableDeviceList failed.",
-                                    t);
-                        }
-                    }
-                }
-            }
-        }
-        catch(Throwable t)
-        {
-            if(t instanceof ThreadDeath)
-                throw(ThreadDeath) t;
-        }
-    }
-
     /**
      * Gets a sample rate supported by a MacCoreaudio device with a specific
      * device index with which it is to be registered with JMF.
@@ -270,97 +58,17 @@ private static double getSupportedSampleRate(
             String deviceUID,
             boolean isEchoCancel)
     {
-        double supportedSampleRate = MacCoreAudioDevice.getNominalSampleRate(
-                deviceUID,
-                false,
-                isEchoCancel);
+        double supportedSampleRate
+            = MacCoreAudioDevice.getNominalSampleRate(
+                    deviceUID,
+                    false,
+                    isEchoCancel);
 
         if(supportedSampleRate >= MediaUtils.MAX_AUDIO_SAMPLE_RATE)
-        {
             supportedSampleRate = MacCoreAudioDevice.DEFAULT_SAMPLE_RATE;
-        }
-
         return supportedSampleRate;
     }
 
-    /**
-     * Waits for all MacCoreaudio clients to finish executing
-     * <tt>OpenStream</tt>.
-     */
-    private static void waitForOpenStream()
-    {
-        boolean interrupted = false;
-
-        while(openStream > 0)
-        {
-            try
-            {
-                openStreamSyncRoot.wait();
-            }
-            catch(InterruptedException ie)
-            {
-                interrupted = true;
-            }
-        }
-        if(interrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Waits for all MacCoreaudio clients to finish executing
-     * <tt>UpdateAvailableDeviceList</tt>.
-     */
-    private static void waitForUpdateAvailableDeviceList()
-    {
-        boolean interrupted = false;
-
-        while (updateAvailableDeviceList > 0)
-        {
-            try
-            {
-                openStreamSyncRoot.wait();
-            }
-            catch (InterruptedException ie)
-            {
-                interrupted = true;
-            }
-        }
-        if (interrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Notifies <tt>MacCoreaudioSystem</tt> that a MacCoreaudio client will
-     * start executing <tt>OpenStream</tt>.
-     */
-    public static void willOpenStream()
-    {
-        synchronized (openStreamSyncRoot)
-        {
-            waitForUpdateAvailableDeviceList();
-
-            openStream++;
-            openStreamSyncRoot.notifyAll();
-        }
-    }
-
-    /**
-     * Notifies <tt>MacCoreaudioSystem</tt> that a MacCoreaudio client will
-     * start executing <tt>UpdateAvailableDeviceList</tt>.
-     */
-    private static void willUpdateAvailableDeviceList()
-    {
-        synchronized(openStreamSyncRoot)
-        {
-            waitForOpenStream();
-
-            updateAvailableDeviceList++;
-            openStreamSyncRoot.notifyAll();
-        }
-
-        fireUpdateAvailableDeviceListEvent(true);
-    }
-
     private Runnable devicesChangedCallback;
 
     /**
@@ -381,41 +89,6 @@ private static void willUpdateAvailableDeviceList()
                     | FEATURE_ECHO_CANCELLATION);
     }
 
-    /**
-     * Sorts a specific list of <tt>CaptureDeviceInfo2</tt>s so that the
-     * ones representing USB devices appear at the beginning/top of the
-     * specified list.
-     *
-     * @param devices the list of <tt>CaptureDeviceInfo2</tt>s to be
-     * sorted so that the ones representing USB devices appear at the
-     * beginning/top of the list
-     */
-    private void bubbleUpUsbDevices(List<CaptureDeviceInfo2> devices)
-    {
-        if(!devices.isEmpty())
-        {
-            List<CaptureDeviceInfo2> nonUsbDevices
-                = new ArrayList<CaptureDeviceInfo2>(devices.size());
-
-            for(Iterator<CaptureDeviceInfo2> i = devices.iterator();
-                    i.hasNext();)
-            {
-                CaptureDeviceInfo2 d = i.next();
-
-                if(!d.isSameTransportType("USB"))
-                {
-                    nonUsbDevices.add(d);
-                    i.remove();
-                }
-            }
-            if(!nonUsbDevices.isEmpty())
-            {
-                for (CaptureDeviceInfo2 d : nonUsbDevices)
-                    devices.add(d);
-            }
-        }
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -426,18 +99,15 @@ protected void doInitialize()
         if(!CoreAudioDevice.isLoaded)
         {
             String message = "MacOSX CoreAudio library is not loaded";
+
             if (logger.isInfoEnabled())
-            {
                 logger.info(message);
-            }
             throw new Exception(message);
         }
 
         // Initializes the library only at the first run.
         if(devicesChangedCallback == null)
-        {
             CoreAudioDevice.initDevices();
-        }
 
         int channels = 1;
         int sampleSizeInBits = 16;
@@ -453,7 +123,6 @@ protected void doInitialize()
             = new LinkedList<CaptureDeviceInfo2>();
         final boolean loggerIsDebugEnabled = logger.isDebugEnabled();
 
-
         String[] deviceUIDList = MacCoreAudioDevice.getDeviceUIDList();
         for(int i = 0; i < deviceUIDList.length; ++i)
         {
@@ -497,12 +166,15 @@ protected void doInitialize()
 
                     if (id.equals(deviceUID) || id.equals(name))
                     {
-                        double rate = ((AudioFormat) existingCdi.getFormats()[0])
-                            .getSampleRate();
-                        if(rate == getSupportedSampleRate(
-                                    true,
-                                    deviceUID,
-                                    isEchoCancelActivated()))
+                        double rate
+                            = ((AudioFormat) existingCdi.getFormats()[0])
+                                .getSampleRate();
+
+                        if(rate
+                                == getSupportedSampleRate(
+                                        true,
+                                        deviceUID,
+                                        isEchoCancel()))
                         {
                             cdi = existingCdi;
                             break;
@@ -526,7 +198,7 @@ protected void doInitialize()
                                     ? getSupportedSampleRate(
                                         true,
                                         deviceUID,
-                                        isEchoCancelActivated())
+                                        isEchoCancel())
                                     : MacCoreAudioDevice.DEFAULT_SAMPLE_RATE,
                                     sampleSizeInBits,
                                     channels,
@@ -644,6 +316,7 @@ else if(isOutputDevice)
             devicesChangedCallback
                 = new Runnable()
                 {
+                    @Override
                     public void run()
                     {
                         try
@@ -676,114 +349,25 @@ protected String getRendererClassName()
     }
 
     /**
-     * Attempts to reorder specific lists of capture and playback/notify
-     * <tt>CaptureDeviceInfo2</tt>s so that devices from the same
-     * hardware appear at the same indices in the respective lists. The judgment
-     * with respect to the belonging to the same hardware is based on the names
-     * of the specified <tt>CaptureDeviceInfo2</tt>s. The implementation
-     * is provided as a fallback to stand in for scenarios in which more
-     * accurate relevant information is not available.
+     * Sets the indicator which determines whether echo cancellation is to be
+     * performed for captured audio.
      *
-     * @param captureDevices
-     * @param playbackDevices
+     * @param echoCancel <tt>true</tt> if echo cancellation is to be performed
+     * for captured audio; otherwise, <tt>false</tt>
      */
-    private void matchDevicesByName(
-            List<CaptureDeviceInfo2> captureDevices,
-            List<CaptureDeviceInfo2> playbackDevices)
+    @Override
+    public void setEchoCancel(boolean echoCancel)
     {
-        Iterator<CaptureDeviceInfo2> captureIter
-            = captureDevices.iterator();
-        Pattern pattern
-            = Pattern.compile(
-                    "array|headphones|microphone|speakers|\\p{Space}|\\(|\\)",
-                    Pattern.CASE_INSENSITIVE);
-        LinkedList<CaptureDeviceInfo2> captureDevicesWithPlayback
-            = new LinkedList<CaptureDeviceInfo2>();
-        LinkedList<CaptureDeviceInfo2> playbackDevicesWithCapture
-            = new LinkedList<CaptureDeviceInfo2>();
-        int count = 0;
-
-        while (captureIter.hasNext())
-        {
-            CaptureDeviceInfo2 captureDevice = captureIter.next();
-            String captureName = captureDevice.getName();
-
-            if (captureName != null)
-            {
-                captureName = pattern.matcher(captureName).replaceAll("");
-                if (captureName.length() != 0)
-                {
-                    Iterator<CaptureDeviceInfo2> playbackIter
-                        = playbackDevices.iterator();
-                    CaptureDeviceInfo2 matchingPlaybackDevice = null;
-
-                    while (playbackIter.hasNext())
-                    {
-                        CaptureDeviceInfo2 playbackDevice
-                            = playbackIter.next();
-                        String playbackName = playbackDevice.getName();
-
-                        if (playbackName != null)
-                        {
-                            playbackName
-                                = pattern
-                                    .matcher(playbackName)
-                                        .replaceAll("");
-                            if (captureName.equals(playbackName))
-                            {
-                                playbackIter.remove();
-                                matchingPlaybackDevice = playbackDevice;
-                                break;
-                            }
-                        }
-                    }
-                    if (matchingPlaybackDevice != null)
-                    {
-                        captureIter.remove();
-                        captureDevicesWithPlayback.add(captureDevice);
-                        playbackDevicesWithCapture.add(
-                                matchingPlaybackDevice);
-                        count++;
-                    }
-                }
-            }
-        }
+        super.setEchoCancel(echoCancel);
 
-        for (int i = count - 1; i >= 0; i--)
+        try
         {
-            captureDevices.add(0, captureDevicesWithPlayback.get(i));
-            playbackDevices.add(0, playbackDevicesWithCapture.get(i));
+            reinitialize();
         }
-    }
-
-    /**
-     * Reinitializes this <tt>MacCoreaudioSystem</tt> in order to bring it up to
-     * date with possible changes in the MacCoreaudio devices. Invokes
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> to update the devices on the
-     * native side and then {@link #initialize()} to reflect any changes on the
-     * Java side. Invoked by MacCoreaudio when it detects that the list of
-     * devices has changed.
-     *
-     * @throws Exception if there was an error during the invocation of
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> and
-     * <tt>DeviceSystem.initialize()</tt>
-     */
-    private void reinitialize()
-        throws Exception
-    {
-        synchronized (updateAvailableDeviceListSyncRoot)
+        catch (Exception e)
         {
-            willUpdateAvailableDeviceList();
-            didUpdateAvailableDeviceList();
+            logger.warn("Failed to reinitialize MacCoreaudio devices", e);
         }
-
-        /*
-         * XXX We will likely minimize the risk of crashes on the native side
-         * even further by invoking initialize() with
-         * Pa_UpdateAvailableDeviceList locked. Unfortunately, that will likely
-         * increase the risks of deadlocks on the Java side.
-         */
-        invokeDeviceSystemInitialize(this);
     }
 
     /**
@@ -798,57 +382,9 @@ public String toString()
         return "Core Audio";
     }
 
-    /**
-     * Returns if the echo canceller has to be activated.
-     *
-     * @return True if the echo canceller has to be activated. False otherwise.
-     */
-    public static boolean isEchoCancelActivated()
-    {
-        boolean isEchoCancel = true;
-
-        ConfigurationService cfg = LibJitsi.getConfigurationService();
-        if (cfg != null)
-            isEchoCancel = cfg.getBoolean(
-                    DeviceConfiguration.PROP_AUDIO_SYSTEM
-                    + "." + LOCATOR_PROTOCOL
-                    + "." + PNAME_ECHOCANCEL,
-                    isEchoCancel);
-
-        return isEchoCancel;
-    }
-
-    /**
-     * Gets the indicator which determines whether echo cancellation is to be
-     * performed for captured audio.
-     *
-     * @return <tt>true</tt> if echo cancellation is to be performed for
-     * captured audio; otherwise, <tt>false</tt>
-     */
-    public boolean isEchoCancel()
-    {
-        // This function is only implemented to disable by default the AEC for
-        // CoreAudio.
-        return isEchoCancelActivated();
-    }
-
-    /**
-     * Sets the indicator which determines whether echo cancellation is to be
-     * performed for captured audio.
-     *
-     * @param echoCancel <tt>true</tt> if echo cancellation is to be performed
-     * for captured audio; otherwise, <tt>false</tt>
-     */
-    public void setEchoCancel(boolean echoCancel)
+    @Override
+    protected void updateAvailableDeviceList()
     {
-        super.setEchoCancel(echoCancel);
-        try
-        {
-            reinitialize();
-        }
-        catch(Exception ex)
-        {
-            logger.warn("Failed to reinitialize MacCoreaudio devices", ex);
-        }
+        // TODO Auto-generated method stub
     }
 }
diff --git a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java
index 9b99e2e6..2d1db5b1 100644
--- a/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java
+++ b/src/org/jitsi/impl/neomedia/device/PortAudioSystem.java
@@ -6,9 +6,7 @@
  */
 package org.jitsi.impl.neomedia.device;
 
-import java.lang.ref.*;
 import java.util.*;
-import java.util.regex.*;
 
 import javax.media.*;
 import javax.media.format.*;
@@ -27,39 +25,8 @@
  * @author Lyubomir Marinov
  */
 public class PortAudioSystem
-    extends AudioSystem
+    extends AudioSystem2
 {
-    /**
-     * Represents a listener which is to be notified before and after
-     * PortAudio's native function <tt>Pa_UpdateAvailableDeviceList()</tt> is
-     * invoked.
-     */
-    public interface PaUpdateAvailableDeviceListListener
-        extends EventListener
-    {
-        /**
-         * Notifies this listener that PortAudio's native function
-         * <tt>Pa_UpdateAvailableDeviceList()</tt> was invoked.
-         *
-         * @throws Exception if this implementation encounters an error. Any
-         * <tt>Throwable</tt> apart from <tt>ThreadDeath</tt> will be ignored
-         * after it is logged for debugging purposes.
-         */
-        void didPaUpdateAvailableDeviceList()
-            throws Exception;
-
-        /**
-         * Notifies this listener that PortAudio's native function
-         * <tt>Pa_UpdateAvailableDeviceList()</tt> will be invoked.
-         *
-         * @throws Exception if this implementation encounters an error. Any
-         * <tt>Throwable</tt> apart from <tt>ThreadDeath</tt> will be ignored
-         * after it is logged for debugging purposes.
-         */
-        void willPaUpdateAvailableDeviceList()
-            throws Exception;
-    }
-
     /**
      * The protocol of the <tt>MediaLocator</tt>s identifying PortAudio
      * <tt>CaptureDevice</tt>s
@@ -73,184 +40,6 @@ void willPaUpdateAvailableDeviceList()
     private static final Logger logger
         = Logger.getLogger(PortAudioSystem.class);
 
-    /**
-     * The number of times that {@link #willPaOpenStream()} has been
-     * invoked without an intervening {@link #didPaOpenStream()} i.e. the
-     * number of PortAudio clients which are currently executing
-     * <tt>Pa_OpenStream</tt> and which are thus inhibiting
-     * <tt>Pa_UpdateAvailableDeviceList</tt>.
-     */
-    private static int paOpenStream = 0;
-
-    /**
-     * The <tt>Object</tt> which synchronizes that access to
-     * {@link #paOpenStream} and {@link #paUpdateAvailableDeviceList}.
-     */
-    private static final Object paOpenStreamSyncRoot = new Object();
-
-    /**
-     * The number of times that {@link #willPaUpdateAvailableDeviceList()}
-     * has been invoked without an intervening
-     * {@link #didPaUpdateAvailableDeviceList()} i.e. the number of
-     * PortAudio clients which are currently executing
-     * <tt>Pa_UpdateAvailableDeviceList</tt> and which are thus inhibiting
-     * <tt>Pa_OpenStream</tt>.
-     */
-    private static int paUpdateAvailableDeviceList = 0;
-
-    /**
-     * The list of <tt>PaUpdateAvailableDeviceListListener</tt>s which are to be
-     * notified before and after PortAudio's native function
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> is invoked.
-     */
-    private static final List<WeakReference<PaUpdateAvailableDeviceListListener>>
-        paUpdateAvailableDeviceListListeners
-            = new LinkedList<WeakReference<PaUpdateAvailableDeviceListListener>>();
-
-    /**
-     * The <tt>Object</tt> which ensures that PortAudio's native function
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> will not be invoked concurrently.
-     * The condition should hold true on the native side but, anyway, it shoul
-     * not hurt (much) to enforce it on the Java side as well.
-     */
-    private static final Object paUpdateAvailableDeviceListSyncRoot
-        = new Object();
-
-    /**
-     * Adds a listener which is to be notified before and after PortAudio's
-     * native function <tt>Pa_UpdateAvailableDeviceList()</tt> is invoked.
-     * <p>
-     * <b>Note</b>: The <tt>PortAudioSystem</tt> class keeps a
-     * <tt>WeakReference</tt> to the specified <tt>listener</tt> in order to
-     * avoid memory leaks.
-     * </p>
-     *
-     * @param listener the <tt>PaUpdateAvailableDeviceListListener</tt> to be
-     * notified before and after PortAudio's native function
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> is invoked
-     */
-    public static void addPaUpdateAvailableDeviceListListener(
-            PaUpdateAvailableDeviceListListener listener)
-    {
-        if (listener == null)
-            throw new NullPointerException("listener");
-
-        synchronized (paUpdateAvailableDeviceListListeners)
-        {
-            Iterator<WeakReference<PaUpdateAvailableDeviceListListener>> i
-                = paUpdateAvailableDeviceListListeners.iterator();
-            boolean add = true;
-
-            while (i.hasNext())
-            {
-                PaUpdateAvailableDeviceListListener l = i.next().get();
-
-                if (l == null)
-                    i.remove();
-                else if (l.equals(listener))
-                    add = false;
-            }
-            if (add)
-            {
-                paUpdateAvailableDeviceListListeners.add(
-                        new WeakReference<PaUpdateAvailableDeviceListListener>(
-                                listener));
-            }
-        }
-    }
-
-    /**
-     * Notifies <tt>PortAudioSystem</tt> that a PortAudio client finished
-     * executing <tt>Pa_OpenStream</tt>.
-     */
-    public static void didPaOpenStream()
-    {
-        synchronized (paOpenStreamSyncRoot)
-        {
-            paOpenStream--;
-            if (paOpenStream < 0)
-                paOpenStream = 0;
-
-            paOpenStreamSyncRoot.notifyAll();
-        }
-    }
-
-    /**
-     * Notifies <tt>PortAudioSystem</tt> that a PortAudio client finished
-     * executing <tt>Pa_UpdateAvailableDeviceList</tt>.
-     */
-    private static void didPaUpdateAvailableDeviceList()
-    {
-        synchronized (paOpenStreamSyncRoot)
-        {
-            paUpdateAvailableDeviceList--;
-            if (paUpdateAvailableDeviceList < 0)
-                paUpdateAvailableDeviceList = 0;
-
-            paOpenStreamSyncRoot.notifyAll();
-        }
-
-        firePaUpdateAvailableDeviceListEvent(false);
-    }
-
-    /**
-     * Notifies the registered <tt>PaUpdateAvailableDeviceListListener</tt>s
-     * that PortAudio's native function <tt>Pa_UpdateAvailableDeviceList()</tt>
-     * will be or was invoked.
-     *
-     * @param will <tt>true</tt> if PortAudio's native function
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> will be invoked or <tt>false</tt>
-     * if it was invoked
-     */
-    private static void firePaUpdateAvailableDeviceListEvent(boolean will)
-    {
-        try
-        {
-            List<WeakReference<PaUpdateAvailableDeviceListListener>> ls;
-
-            synchronized (paUpdateAvailableDeviceListListeners)
-            {
-                ls
-                    = new ArrayList<WeakReference<PaUpdateAvailableDeviceListListener>>(
-                            paUpdateAvailableDeviceListListeners);
-            }
-
-            for (WeakReference<PaUpdateAvailableDeviceListListener> wr : ls)
-            {
-                PaUpdateAvailableDeviceListListener l = wr.get();
-
-                if (l != null)
-                {
-                    try
-                    {
-                        if (will)
-                            l.willPaUpdateAvailableDeviceList();
-                        else
-                            l.didPaUpdateAvailableDeviceList();
-                    }
-                    catch (Throwable t)
-                    {
-                        if (t instanceof ThreadDeath)
-                            throw (ThreadDeath) t;
-                        else
-                        {
-                            logger.error(
-                                    "PaUpdateAvailableDeviceListListener."
-                                        + (will ? "will" : "did")
-                                        + "PaUpdateAvailableDeviceList failed.",
-                                    t);
-                        }
-                    }
-                }
-            }
-        }
-        catch (Throwable t)
-        {
-            if (t instanceof ThreadDeath)
-                throw (ThreadDeath) t;
-        }
-    }
-
     /**
      * Gets a sample rate supported by a PortAudio device with a specific device
      * index with which it is to be registered with JMF.
@@ -349,105 +138,6 @@ public static void monitorFunctionalHealth(
         // TODO Auto-generated method stub
     }
 
-    public static void removePaUpdateAvailableDeviceListListener(
-            PaUpdateAvailableDeviceListListener listener)
-    {
-        if (listener == null)
-            return;
-
-        synchronized (paUpdateAvailableDeviceListListeners)
-        {
-            Iterator<WeakReference<PaUpdateAvailableDeviceListListener>> i
-                = paUpdateAvailableDeviceListListeners.iterator();
-
-            while (i.hasNext())
-            {
-                PaUpdateAvailableDeviceListListener l = i.next().get();
-
-                if ((l == null) || l.equals(listener))
-                    i.remove();
-            }
-        }
-    }
-
-    /**
-     * Waits for all PortAudio clients to finish executing
-     * <tt>Pa_OpenStream</tt>.
-     */
-    private static void waitForPaOpenStream()
-    {
-        boolean interrupted = false;
-
-        while (paOpenStream > 0)
-        {
-            try
-            {
-                paOpenStreamSyncRoot.wait();
-            }
-            catch (InterruptedException ie)
-            {
-                interrupted = true;
-            }
-        }
-        if (interrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Waits for all PortAudio clients to finish executing
-     * <tt>Pa_UpdateAvailableDeviceList</tt>.
-     */
-    private static void waitForPaUpdateAvailableDeviceList()
-    {
-        boolean interrupted = false;
-
-        while (paUpdateAvailableDeviceList > 0)
-        {
-            try
-            {
-                paOpenStreamSyncRoot.wait();
-            }
-            catch (InterruptedException ie)
-            {
-                interrupted = true;
-            }
-        }
-        if (interrupted)
-            Thread.currentThread().interrupt();
-    }
-
-    /**
-     * Notifies <tt>PortAudioSystem</tt> that a PortAudio client will start
-     * executing <tt>Pa_OpenStream</tt>.
-     */
-    public static void willPaOpenStream()
-    {
-        synchronized (paOpenStreamSyncRoot)
-        {
-            waitForPaUpdateAvailableDeviceList();
-
-            paOpenStream++;
-            paOpenStreamSyncRoot.notifyAll();
-        }
-    }
-
-    /**
-     * Notifies <tt>PortAudioSystem</tt> that a PortAudio client will start
-     * executing <tt>Pa_UpdateAvailableDeviceList</tt>.
-     */
-    private static void willPaUpdateAvailableDeviceList()
-    {
-        synchronized (paOpenStreamSyncRoot)
-        {
-            waitForPaOpenStream();
-
-            paUpdateAvailableDeviceList++;
-            paOpenStreamSyncRoot.notifyAll();
-        }
-
-        firePaUpdateAvailableDeviceListEvent(true);
-    }
-
     private Runnable devicesChangedCallback;
 
     /**
@@ -469,41 +159,6 @@ private static void willPaUpdateAvailableDeviceList()
                     | FEATURE_REINITIALIZE);
     }
 
-    /**
-     * Sorts a specific list of <tt>CaptureDeviceInfo2</tt>s so that the
-     * ones representing USB devices appear at the beginning/top of the
-     * specified list.
-     *
-     * @param devices the list of <tt>CaptureDeviceInfo2</tt>s to be
-     * sorted so that the ones representing USB devices appear at the
-     * beginning/top of the list
-     */
-    private void bubbleUpUsbDevices(List<CaptureDeviceInfo2> devices)
-    {
-        if (!devices.isEmpty())
-        {
-            List<CaptureDeviceInfo2> nonUsbDevices
-                = new ArrayList<CaptureDeviceInfo2>(devices.size());
-
-            for (Iterator<CaptureDeviceInfo2> i = devices.iterator();
-                    i.hasNext();)
-            {
-                CaptureDeviceInfo2 d = i.next();
-
-                if (!d.isSameTransportType("USB"))
-                {
-                    nonUsbDevices.add(d);
-                    i.remove();
-                }
-            }
-            if (!nonUsbDevices.isEmpty())
-            {
-                for (CaptureDeviceInfo2 d : nonUsbDevices)
-                    devices.add(d);
-            }
-        }
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -725,6 +380,7 @@ else if (maxOutputChannels > 0)
             devicesChangedCallback
                 = new Runnable()
                 {
+                    @Override
                     public void run()
                     {
                         try
@@ -755,124 +411,6 @@ protected String getRendererClassName()
         return PortAudioRenderer.class.getName();
     }
 
-    /**
-     * Attempts to reorder specific lists of capture and playback/notify
-     * <tt>CaptureDeviceInfo2</tt>s so that devices from the same
-     * hardware appear at the same indices in the respective lists. The judgment
-     * with respect to the belonging to the same hardware is based on the names
-     * of the specified <tt>CaptureDeviceInfo2</tt>s. The implementation
-     * is provided as a fallback to stand in for scenarios in which more
-     * accurate relevant information is not available.
-     *
-     * @param captureDevices
-     * @param playbackDevices
-     */
-    private void matchDevicesByName(
-            List<CaptureDeviceInfo2> captureDevices,
-            List<CaptureDeviceInfo2> playbackDevices)
-    {
-        Iterator<CaptureDeviceInfo2> captureIter
-            = captureDevices.iterator();
-        Pattern pattern
-            = Pattern.compile(
-                    "array|headphones|microphone|speakers|\\p{Space}|\\(|\\)",
-                    Pattern.CASE_INSENSITIVE);
-        LinkedList<CaptureDeviceInfo2> captureDevicesWithPlayback
-            = new LinkedList<CaptureDeviceInfo2>();
-        LinkedList<CaptureDeviceInfo2> playbackDevicesWithCapture
-            = new LinkedList<CaptureDeviceInfo2>();
-        int count = 0;
-
-        while (captureIter.hasNext())
-        {
-            CaptureDeviceInfo2 captureDevice = captureIter.next();
-            String captureName = captureDevice.getName();
-
-            if (captureName != null)
-            {
-                captureName = pattern.matcher(captureName).replaceAll("");
-                if (captureName.length() != 0)
-                {
-                    Iterator<CaptureDeviceInfo2> playbackIter
-                        = playbackDevices.iterator();
-                    CaptureDeviceInfo2 matchingPlaybackDevice = null;
-
-                    while (playbackIter.hasNext())
-                    {
-                        CaptureDeviceInfo2 playbackDevice
-                            = playbackIter.next();
-                        String playbackName = playbackDevice.getName();
-
-                        if (playbackName != null)
-                        {
-                            playbackName
-                                = pattern
-                                    .matcher(playbackName)
-                                        .replaceAll("");
-                            if (captureName.equals(playbackName))
-                            {
-                                playbackIter.remove();
-                                matchingPlaybackDevice = playbackDevice;
-                                break;
-                            }
-                        }
-                    }
-                    if (matchingPlaybackDevice != null)
-                    {
-                        captureIter.remove();
-                        captureDevicesWithPlayback.add(captureDevice);
-                        playbackDevicesWithCapture.add(
-                                matchingPlaybackDevice);
-                        count++;
-                    }
-                }
-            }
-        }
-
-        for (int i = count - 1; i >= 0; i--)
-        {
-            captureDevices.add(0, captureDevicesWithPlayback.get(i));
-            playbackDevices.add(0, playbackDevicesWithCapture.get(i));
-        }
-    }
-
-    /**
-     * Reinitializes this <tt>PortAudioSystem</tt> in order to bring it up to
-     * date with possible changes in the PortAudio devices. Invokes
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> to update the devices on the
-     * native side and then {@link #initialize()} to reflect any changes on the
-     * Java side. Invoked by PortAudio when it detects that the list of devices
-     * has changed.
-     *
-     * @throws Exception if there was an error during the invocation of
-     * <tt>Pa_UpdateAvailableDeviceList()</tt> and
-     * <tt>DeviceSystem.initialize()</tt>
-     */
-    private void reinitialize()
-        throws Exception
-    {
-        synchronized (paUpdateAvailableDeviceListSyncRoot)
-        {
-            willPaUpdateAvailableDeviceList();
-            try
-            {
-                Pa.UpdateAvailableDeviceList();
-            }
-            finally
-            {
-                didPaUpdateAvailableDeviceList();
-            }
-        }
-
-        /*
-         * XXX We will likely minimize the risk of crashes on the native side
-         * even further by invoking initialize() with
-         * Pa_UpdateAvailableDeviceList locked. Unfortunately, that will likely
-         * increase the risks of deadlocks on the Java side.
-         */
-        invokeDeviceSystemInitialize(this);
-    }
-
     /**
      * {@inheritDoc}
      *
@@ -884,4 +422,10 @@ public String toString()
     {
         return "PortAudio";
     }
+
+    @Override
+    protected void updateAvailableDeviceList()
+    {
+        Pa.UpdateAvailableDeviceList();
+    }
 }
diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/maccoreaudio/MacCoreaudioStream.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/maccoreaudio/MacCoreaudioStream.java
index 04cef0bf..b372453e 100644
--- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/maccoreaudio/MacCoreaudioStream.java
+++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/maccoreaudio/MacCoreaudioStream.java
@@ -44,6 +44,12 @@ public class MacCoreaudioStream
     @SuppressWarnings("unused") // under development
     private final boolean audioQualityImprovement;
 
+    /**
+     * The buffer which stores the outgoing data before sending them to
+     * the RTP stack.
+     */
+    private byte[] buffer = null;
+
     /**
      * The number of bytes to read from a native MacCoreaudio stream in a single
      * invocation. Based on {@link #framesPerBuffer}.
@@ -58,16 +64,10 @@ public class MacCoreaudioStream
     private String deviceUID;
 
     /**
-     * A mutual eclusion used to avoid conflict when starting / stoping the
-     * stream for this stream;
-     */
-    private Object startStopMutex = new Object();
-
-    /**
-     * The buffer which stores the outgoing data before sending them to
-     * the RTP stack.
+     * The last-known <tt>Format</tt> of the media data made available by this
+     * <tt>PullBufferStream</tt>.
      */
-    private byte[] buffer = null;
+    private AudioFormat format = null;
 
     /**
      * A list of already allocated buffers, ready to accept new captured data.
@@ -80,22 +80,27 @@ public class MacCoreaudioStream
      */
     private Vector<byte[]> fullBufferList = new Vector<byte[]>();
 
+    /**
+     * The <tt>GainControl</tt> through which the volume/gain of captured media
+     * is controlled.
+     */
+    private final GainControl gainControl;
+
     /**
      * The number of data available to feed the RTP stack.
      */
     private int nbBufferData = 0;
 
     /**
-     * The last-known <tt>Format</tt> of the media data made available by this
-     * <tt>PullBufferStream</tt>.
+     * Current sequence number.
      */
-    private AudioFormat format = null;
+    private int sequenceNumber = 0;
 
     /**
-     * The <tt>GainControl</tt> through which the volume/gain of captured media
-     * is controlled.
+     * A mutual eclusion used to avoid conflict when starting / stoping the
+     * stream for this stream;
      */
-    private final GainControl gainControl;
+    private Object startStopMutex = new Object();
 
     /**
      * Locked when currently stopping the stream. Prevents deadlock between the
@@ -103,9 +108,14 @@ public class MacCoreaudioStream
      */
     private Lock stopLock = new ReentrantLock();
 
-    private final MacCoreaudioSystem.UpdateAvailableDeviceListListener
+    /**
+     * The stream structure used by the native maccoreaudio library.
+     */
+    private long stream = 0;
+
+    private final UpdateAvailableDeviceListListener
         updateAvailableDeviceListListener
-            = new MacCoreaudioSystem.UpdateAvailableDeviceListListener()
+            = new UpdateAvailableDeviceListListener()
             {
                 /**
                  * The device ID (could be deviceUID or name but that is not
@@ -116,6 +126,7 @@ public class MacCoreaudioStream
 
                 private boolean start = false;
 
+                @Override
                 public void didUpdateAvailableDeviceList()
                     throws Exception
                 {
@@ -131,6 +142,7 @@ public void didUpdateAvailableDeviceList()
                     }
                 }
 
+                @Override
                 public void willUpdateAvailableDeviceList()
                     throws Exception
                 {
@@ -152,16 +164,6 @@ public void willUpdateAvailableDeviceList()
                 }
             };
 
-    /**
-     * Current sequence number.
-     */
-    private int sequenceNumber = 0;
-
-    /**
-     * The stream structure used by the native maccoreaudio library.
-     */
-    private long stream = 0;
-
     /**
      * Initializes a new <tt>MacCoreaudioStream</tt> instance which is to have
      * its <tt>Format</tt>-related information abstracted by a specific
@@ -194,8 +196,16 @@ public MacCoreaudioStream(
         // XXX We will add a UpdateAvailableDeviceListListener and will not
         // remove it because we will rely on MacCoreaudioSystem's use of
         // WeakReference.
-        MacCoreaudioSystem.addUpdateAvailableDeviceListListener(
-                updateAvailableDeviceListListener);
+        AudioSystem2 audioSystem
+            = (AudioSystem2)
+                AudioSystem.getAudioSystem(
+                        AudioSystem.LOCATOR_PROTOCOL_MACCOREAUDIO);
+
+        if (audioSystem != null)
+        {
+            audioSystem.addUpdateAvailableDeviceListListener(
+                    updateAvailableDeviceListListener);
+        }
     }
 
     private void connect()
@@ -306,6 +316,66 @@ public void read(Buffer buffer)
         buffer.setTimeStamp(bufferTimeStamp);
     }
 
+    /**
+     * Callback which receives the data from the coreaudio library.
+     *
+     * @param buffer The data captured from the input.
+     * @param bufferLength The length of the data captured.
+     */
+    public void readInput(byte[] buffer, int bufferLength)
+    {
+        int nbCopied = 0;
+        while(bufferLength > 0)
+        {
+            int length = this.buffer.length - nbBufferData;
+            if(bufferLength < length)
+            {
+                length = bufferLength;
+            }
+
+            System.arraycopy(
+                    buffer,
+                    nbCopied,
+                    this.buffer,
+                    nbBufferData,
+                    length);
+
+            nbBufferData += length;
+            nbCopied += length;
+            bufferLength -= length;
+
+            if(nbBufferData == this.buffer.length)
+            {
+                this.fullBufferList.add(this.buffer);
+                this.buffer = null;
+                nbBufferData = 0;
+                if(stopLock.tryLock())
+                {
+                    try
+                    {
+                        synchronized(startStopMutex)
+                        {
+                            startStopMutex.notify();
+                            if(this.freeBufferList.size() > 0)
+                            {
+                                this.buffer = this.freeBufferList.remove(0);
+                            }
+                        }
+                    }
+                    finally
+                    {
+                        stopLock.unlock();
+                    }
+                }
+
+                if(this.buffer == null)
+                {
+                    this.buffer = new byte[bytesPerBuffer];
+                }
+            }
+        }
+    }
+
     /**
      * Sets the device index of the MacCoreaudio device to be read through this
      * <tt>PullBufferStream</tt>.
@@ -362,19 +432,35 @@ public void start()
                 this.fullBufferList.clear();
                 this.freeBufferList.clear();
 
-                MacCoreaudioSystem.willOpenStream();
-                stream = MacCoreAudioDevice.startStream(
-                        deviceUID,
-                        this,
-                        (float) format.getSampleRate(),
-                        format.getChannels(),
-                        format.getSampleSizeInBits(),
-                        false,
-                        format.getEndian() == AudioFormat.BIG_ENDIAN,
-                        false,
-                        true,
-                        MacCoreaudioSystem.isEchoCancelActivated());
-                MacCoreaudioSystem.didOpenStream();
+                AudioSystem2 audioSystem
+                    = (AudioSystem2)
+                        AudioSystem.getAudioSystem(
+                                AudioSystem.LOCATOR_PROTOCOL_MACCOREAUDIO);
+
+                if (audioSystem != null)
+                    audioSystem.willOpenStream();
+                try
+                {
+                    stream
+                        = MacCoreAudioDevice.startStream(
+                                deviceUID,
+                                this,
+                                (float) format.getSampleRate(),
+                                format.getChannels(),
+                                format.getSampleSizeInBits(),
+                                false,
+                                format.getEndian() == AudioFormat.BIG_ENDIAN,
+                                false,
+                                true,
+                                (audioSystem == null)
+                                    ? true
+                                    : audioSystem.isEchoCancel());
+                }
+                finally
+                {
+                    if (audioSystem != null)
+                        audioSystem.didOpenStream();
+                }
             }
         }
     }
@@ -407,64 +493,4 @@ public void stop()
             stopLock.unlock();
         }
     }
-
-    /**
-     * Callback which receives the data from the coreaudio library.
-     *
-     * @param buffer The data captured from the input.
-     * @param bufferLength The length of the data captured.
-     */
-    public void readInput(byte[] buffer, int bufferLength)
-    {
-        int nbCopied = 0;
-        while(bufferLength > 0)
-        {
-            int length = this.buffer.length - nbBufferData;
-            if(bufferLength < length)
-            {
-                length = bufferLength;
-            }
-
-            System.arraycopy(
-                    buffer,
-                    nbCopied,
-                    this.buffer,
-                    nbBufferData,
-                    length);
-
-            nbBufferData += length;
-            nbCopied += length;
-            bufferLength -= length;
-
-            if(nbBufferData == this.buffer.length)
-            {
-                this.fullBufferList.add(this.buffer);
-                this.buffer = null;
-                nbBufferData = 0;
-                if(stopLock.tryLock())
-                {
-                    try
-                    {
-                        synchronized(startStopMutex)
-                        {
-                            startStopMutex.notify();
-                            if(this.freeBufferList.size() > 0)
-                            {
-                                this.buffer = this.freeBufferList.remove(0);
-                            }
-                        }
-                    }
-                    finally
-                    {
-                        stopLock.unlock();
-                    }
-                }
-
-                if(this.buffer == null)
-                {
-                    this.buffer = new byte[bytesPerBuffer];
-                }
-            }
-        }
-    }
 }
diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java
index 5b7a149a..8c4e1f1c 100644
--- a/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java
+++ b/src/org/jitsi/impl/neomedia/jmfext/media/protocol/portaudio/PortAudioStream.java
@@ -43,6 +43,26 @@ public class PortAudioStream
      */
     private static final long NEVER = DiagnosticsControl.NEVER;
 
+    /**
+     * Causes the currently executing thread to temporarily pause and allow
+     * other threads to execute.
+     */
+    public static void yield()
+    {
+        boolean interrupted = false;
+
+        try
+        {
+            Thread.sleep(Pa.DEFAULT_MILLIS_PER_BUFFER);
+        }
+        catch (InterruptedException ie)
+        {
+            interrupted = true;
+        }
+        if (interrupted)
+            Thread.currentThread().interrupt();
+    }
+
     /**
      * The indicator which determines whether audio quality improvement is
      * enabled for this <tt>PortAudioStream</tt> in accord with the preferences
@@ -145,9 +165,9 @@ public String toString()
      */
     private long inputParameters = 0;
 
-    private final PortAudioSystem.PaUpdateAvailableDeviceListListener
+    private final UpdateAvailableDeviceListListener
         paUpdateAvailableDeviceListListener
-            = new PortAudioSystem.PaUpdateAvailableDeviceListListener()
+            = new UpdateAvailableDeviceListListener()
             {
                 /**
                  * The device ID (could be deviceUID or name but that is not
@@ -158,7 +178,8 @@ public String toString()
 
                 private boolean start = false;
 
-                public void didPaUpdateAvailableDeviceList()
+                @Override
+                public void didUpdateAvailableDeviceList()
                     throws Exception
                 {
                     synchronized (PortAudioStream.this)
@@ -192,7 +213,8 @@ public void didPaUpdateAvailableDeviceList()
                     }
                 }
 
-                public void willPaUpdateAvailableDeviceList()
+                @Override
+                public void willUpdateAvailableDeviceList()
                     throws Exception
                 {
                     synchronized (PortAudioStream.this)
@@ -290,12 +312,20 @@ public PortAudioStream(
                 : (GainControl) mediaServiceImpl.getInputVolumeControl();
 
         /*
-         * XXX We will add a PaUpdateAvailableDeviceListListener and will not
+         * XXX We will add a UpdateAvailableDeviceListListener and will not
          * remove it because we will rely on PortAudioSystem's use of
          * WeakReference.
          */
-        PortAudioSystem.addPaUpdateAvailableDeviceListListener(
-                paUpdateAvailableDeviceListListener);
+        AudioSystem2 audioSystem
+            = (AudioSystem2)
+                AudioSystem.getAudioSystem(
+                        AudioSystem.LOCATOR_PROTOCOL_PORTAUDIO);
+
+        if (audioSystem != null)
+        {
+            audioSystem.addUpdateAvailableDeviceListListener(
+                    paUpdateAvailableDeviceListListener);
+        }
     }
 
     private void connect()
@@ -309,8 +339,7 @@ private void connect()
         if (deviceIndex == Pa.paNoDevice)
         {
             throw new IOException(
-                    "The audio device "
-                        + deviceID
+                    "The audio device " + deviceID
                         + " appears to be disconnected.");
         }
 
@@ -715,14 +744,21 @@ synchronized void setDeviceID(String deviceID)
         // DataSource#connect
         if (this.deviceID != null)
         {
-            PortAudioSystem.willPaOpenStream();
+            AudioSystem2 audioSystem
+                = (AudioSystem2)
+                    AudioSystem.getAudioSystem(
+                            AudioSystem.LOCATOR_PROTOCOL_PORTAUDIO);
+
+            if (audioSystem != null)
+                audioSystem.willOpenStream();
             try
             {
                 connect();
             }
             finally
             {
-                PortAudioSystem.didPaOpenStream();
+                if (audioSystem != null)
+                    audioSystem.didOpenStream();
             }
         }
     }
@@ -839,24 +875,4 @@ private void waitWhileStreamIsBusy()
         if (interrupted)
             Thread.currentThread().interrupt();
     }
-
-    /**
-     * Causes the currently executing thread to temporarily pause and allow
-     * other threads to execute.
-     */
-    public static void yield()
-    {
-        boolean interrupted = false;
-
-        try
-        {
-            Thread.sleep(Pa.DEFAULT_MILLIS_PER_BUFFER);
-        }
-        catch (InterruptedException ie)
-        {
-            interrupted = true;
-        }
-        if (interrupted)
-            Thread.currentThread().interrupt();
-    }
 }
diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/MacCoreaudioRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/MacCoreaudioRenderer.java
index 5edf0d33..f29acf47 100644
--- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/MacCoreaudioRenderer.java
+++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/MacCoreaudioRenderer.java
@@ -117,40 +117,42 @@ public class MacCoreaudioRenderer
      * corruption afterwards and it will attempt to restore the state of this
      * <tt>Renderer</tt> after the invocation.
      */
-    private final MacCoreaudioSystem.UpdateAvailableDeviceListListener
+    private final UpdateAvailableDeviceListListener
         updateAvailableDeviceListListener
-            = new MacCoreaudioSystem.UpdateAvailableDeviceListListener()
-    {
-        private boolean start = false;
-
-        public void didUpdateAvailableDeviceList()
-            throws Exception
-        {
-            synchronized(startStopMutex)
+            = new UpdateAvailableDeviceListListener()
             {
-                updateDeviceUID();
-                if(start)
+                private boolean start = false;
+
+                @Override
+                public void didUpdateAvailableDeviceList()
+                    throws Exception
                 {
-                    open();
-                    start();
+                    synchronized(startStopMutex)
+                    {
+                        updateDeviceUID();
+                        if(start)
+                        {
+                            open();
+                            start();
+                        }
+                    }
                 }
-            }
-        }
 
-        public void willUpdateAvailableDeviceList()
-            throws Exception
-        {
-            synchronized(startStopMutex)
-            {
-                start = false;
-                if(stream != 0)
+                @Override
+                public void willUpdateAvailableDeviceList()
+                    throws Exception
                 {
-                    start = true;
-                    stop();
+                    synchronized(startStopMutex)
+                    {
+                        start = false;
+                        if(stream != 0)
+                        {
+                            start = true;
+                            stop();
+                        }
+                    }
                 }
-            }
-        }
-    };
+            };
 
     /**
      * Array of supported input formats.
@@ -180,11 +182,14 @@ public MacCoreaudioRenderer(boolean enableVolumeControl)
                     ? AudioSystem.DataFlow.PLAYBACK
                     : AudioSystem.DataFlow.NOTIFY);
 
-        // XXX We will add a PaUpdateAvailableDeviceListListener and will not
+        // XXX We will add an UpdateAvailableDeviceListListener and will not
         // remove it because we will rely on MacCoreaudioSystem's use of
         // WeakReference.
-        MacCoreaudioSystem.addUpdateAvailableDeviceListListener(
-                updateAvailableDeviceListListener);
+        if (audioSystem != null)
+        {
+            audioSystem.addUpdateAvailableDeviceListListener(
+                    updateAvailableDeviceListListener);
+        }
     }
 
     /**
@@ -269,14 +274,17 @@ private void getSupportedInputFormats(
         AudioFormat audioFormat = (AudioFormat) format;
         int sampleSizeInBits = audioFormat.getSampleSizeInBits();
         double sampleRate = audioFormat.getSampleRate();
-        float minRate = MacCoreAudioDevice.getMinimalNominalSampleRate(
-                deviceUID,
-                true,
-                MacCoreaudioSystem.isEchoCancelActivated());
-        float maxRate = MacCoreAudioDevice.getMaximalNominalSampleRate(
-                deviceUID,
-                true,
-                MacCoreaudioSystem.isEchoCancelActivated());
+        boolean isEchoCancel = audioSystem.isEchoCancel();
+        float minRate
+            = MacCoreAudioDevice.getMinimalNominalSampleRate(
+                    deviceUID,
+                    true,
+                    isEchoCancel);
+        float maxRate
+            = MacCoreAudioDevice.getMaximalNominalSampleRate(
+                    deviceUID,
+                    true,
+                    isEchoCancel);
 
         for(int channels = minOutputChannels;
                 channels <= maxOutputChannels;
@@ -314,7 +322,7 @@ public void open()
         {
             if(stream == 0)
             {
-                MacCoreaudioSystem.willOpenStream();
+                audioSystem.willOpenStream();
                 try
                 {
                     if(!this.updateDeviceUID())
@@ -331,7 +339,7 @@ public void open()
                 }
                 finally
                 {
-                    MacCoreaudioSystem.didOpenStream();
+                    audioSystem.didOpenStream();
                 }
 
             }
@@ -448,19 +456,27 @@ public void start()
                 if (nbChannels == Format.NOT_SPECIFIED)
                     nbChannels = 1;
 
-                MacCoreaudioSystem.willOpenStream();
-                stream = MacCoreAudioDevice.startStream(
-                        deviceUID,
-                        this,
-                        (float) inputFormat.getSampleRate(),
-                        nbChannels,
-                        inputFormat.getSampleSizeInBits(),
-                        false,
-                        inputFormat.getEndian() == AudioFormat.BIG_ENDIAN,
-                        false,
-                        false,
-                        MacCoreaudioSystem.isEchoCancelActivated());
-                MacCoreaudioSystem.didOpenStream();
+                audioSystem.willOpenStream();
+                try
+                {
+                    stream
+                        = MacCoreAudioDevice.startStream(
+                                deviceUID,
+                                this,
+                                (float) inputFormat.getSampleRate(),
+                                nbChannels,
+                                inputFormat.getSampleSizeInBits(),
+                                false,
+                                inputFormat.getEndian()
+                                    == AudioFormat.BIG_ENDIAN,
+                                false,
+                                false,
+                                audioSystem.isEchoCancel());
+                }
+                finally
+                {
+                    audioSystem.didOpenStream();
+                }
             }
         }
     }
diff --git a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
index 18f2d08a..a1fb9425 100644
--- a/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
+++ b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
@@ -210,11 +210,12 @@ public String toString()
      * corruption afterwards and it will attempt to restore the state of this
      * <tt>Renderer</tt> after the invocation.
      */
-    private final PortAudioSystem.PaUpdateAvailableDeviceListListener
+    private final UpdateAvailableDeviceListListener
         paUpdateAvailableDeviceListListener
-            = new PortAudioSystem.PaUpdateAvailableDeviceListListener()
+            = new UpdateAvailableDeviceListListener()
             {
-                public void didPaUpdateAvailableDeviceList()
+                @Override
+                public void didUpdateAvailableDeviceList()
                     throws Exception
                 {
                     synchronized (PortAudioRenderer.this)
@@ -248,7 +249,8 @@ public void didPaUpdateAvailableDeviceList()
                     }
                 }
 
-                public void willPaUpdateAvailableDeviceList()
+                @Override
+                public void willUpdateAvailableDeviceList()
                     throws Exception
                 {
                     synchronized (PortAudioRenderer.this)
@@ -335,8 +337,11 @@ public PortAudioRenderer(boolean enableVolumeControl)
          * remove it because we will rely on PortAudioSystem's use of
          * WeakReference.
          */
-        PortAudioSystem.addPaUpdateAvailableDeviceListListener(
-                paUpdateAvailableDeviceListListener);
+        if (audioSystem != null)
+        {
+            audioSystem.addUpdateAvailableDeviceListListener(
+                    paUpdateAvailableDeviceListListener);
+        }
     }
 
     /**
@@ -520,14 +525,14 @@ public synchronized void open()
     {
         try
         {
-            PortAudioSystem.willPaOpenStream();
+            audioSystem.willOpenStream();
             try
             {
                 doOpen();
             }
             finally
             {
-                PortAudioSystem.didPaOpenStream();
+                audioSystem.didOpenStream();
             }
         }
         catch (Throwable t)
diff --git a/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java b/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java
index 2efb4c0b..3a428ce4 100644
--- a/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java
+++ b/src/org/jitsi/impl/neomedia/protocol/PushBufferDataSourceAdapter.java
@@ -122,6 +122,7 @@ void close()
          * @return <tt>true</tt> if the wrapped <tt>PullBufferStream</tt> has
          * reached the end of the media data; otherwise, <tt>false</tt>
          */
+        @Override
         public boolean endOfStream()
         {
             return stream.endOfStream();
@@ -135,6 +136,7 @@ public boolean endOfStream()
          * <tt>PullBufferStream</tt> which describes the type of the media data
          * it gives access to
          */
+        @Override
         public ContentDescriptor getContentDescriptor()
         {
             return stream.getContentDescriptor();
@@ -147,6 +149,7 @@ public ContentDescriptor getContentDescriptor()
          * @return the length of the content the wrapped
          * <tt>PullBufferStream</tt> gives access to
          */
+        @Override
         public long getContentLength()
         {
             return stream.getContentLength();
@@ -165,6 +168,7 @@ public long getContentLength()
          * if the wrapped <tt>PushBufferStream</tt> does not have a control of
          * the specified type
          */
+        @Override
         public Object getControl(String controlType)
         {
             return stream.getControl(controlType);
@@ -177,6 +181,7 @@ public Object getControl(String controlType)
          * @return an array of <tt>Object</tt>s which represent the controls
          * available for the wrapped <tt>PushBufferStream</tt>
          */
+        @Override
         public Object[] getControls()
         {
             return stream.getControls();
@@ -188,6 +193,7 @@ public Object[] getControls()
          *
          * @return the <tt>Format</tt> of the wrapped <tt>PullBufferStream</tt>
          */
+        @Override
         public Format getFormat()
         {
             return stream.getFormat();
@@ -202,6 +208,7 @@ public Format getFormat()
          * data from this <tt>PushBufferDataSource</tt> into the specified
          * <tt>buffer</tt>
          */
+        @Override
         public void read(Buffer buffer)
             throws IOException
         {
@@ -284,6 +291,7 @@ else if (yield)
          * which <tt>PushBufferStream</tt> is to notify its user that media data
          * is available for reading
          */
+        @Override
         public void setTransferHandler(BufferTransferHandler transferHandler)
         {
             if (this.transferHandler != transferHandler)
@@ -562,7 +570,9 @@ else if (format instanceof VideoFormat)
         }
         catch (Throwable t)
         {
-            if (t instanceof ThreadDeath)
+            if (t instanceof InterruptedException)
+                Thread.currentThread().interrupt();
+            else if (t instanceof ThreadDeath)
                 throw (ThreadDeath) t;
 
             logger.warn("Failed to set the priority of streamReadThread");
-- 
GitLab