From e0ffd2963434d0a27c8cd07ceee41371b392f4a5 Mon Sep 17 00:00:00 2001
From: Lyubomir Marinov <lyubomir.marinov@jitsi.org>
Date: Tue, 4 Dec 2012 18:55:36 +0000
Subject: [PATCH] Shortens the time it takes the PortAudio integration on
 Windows/WMME to react to the detection that an audio device has been
 unplugging.

---
 .../protocol/portaudio/PortAudioStream.java   | 55 +++++++++++++------
 .../renderer/audio/PortAudioRenderer.java     | 17 +++++-
 src/org/jitsi/impl/neomedia/portaudio/Pa.java | 10 +++-
 3 files changed, 61 insertions(+), 21 deletions(-)

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 4b75cbbc..0871f2e5 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
@@ -376,21 +376,12 @@ else if (!started)
          */
         if (message != null)
         {
-            boolean interrupted = false;
-
-            try
-            {
-                Thread.sleep(Pa.DEFAULT_MILLIS_PER_BUFFER);
-            }
-            catch (InterruptedException ie)
-            {
-                interrupted = true;
-            }
-            if (interrupted)
-                Thread.currentThread().interrupt();
+            yield();
             throw new IOException(message);
         }
 
+        long paErrorCode = Pa.paNoError;
+
         try
         {
             /*
@@ -416,14 +407,16 @@ else if (!started)
             {
                 Pa.ReadStream(stream, bufferData, framesPerBuffer);
             }
-            catch (PortAudioException paex)
+            catch (PortAudioException pae)
             {
-                logger.error("Failed to read from PortAudio stream.", paex);
+                paErrorCode = pae.getErrorCode();
 
-                IOException ioex = new IOException(paex.getLocalizedMessage());
+                logger.error("Failed to read from PortAudio stream.", pae);
 
-                ioex.initCause(paex);
-                throw ioex;
+                IOException ioe = new IOException(pae.getLocalizedMessage());
+
+                ioe.initCause(pae);
+                throw ioe;
             }
 
             // if we have some volume setting apply them
@@ -452,6 +445,14 @@ else if (!started)
                streamIsBusy = false;
                notifyAll();
             }
+
+            /*
+             * If a timeout has occurred in the method Pa.ReadStream, give the
+             * application a little time to allow it to possibly get its act
+             * together.
+             */
+            if (Pa.paTimedOut == paErrorCode)
+                yield();
         }
     }
 
@@ -618,4 +619,24 @@ 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/PortAudioRenderer.java b/src/org/jitsi/impl/neomedia/jmfext/media/renderer/audio/PortAudioRenderer.java
index 1c176cee..1a6ebc2a 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
@@ -670,6 +670,9 @@ public int process(Buffer buffer)
             else
                 streamIsBusy = true;
         }
+
+        long paErrorCode = Pa.paNoError;
+
         try
         {
             process(
@@ -677,9 +680,11 @@ public int process(Buffer buffer)
                 buffer.getOffset(),
                 buffer.getLength());
         }
-        catch (PortAudioException paex)
+        catch (PortAudioException pae)
         {
-            logger.error("Failed to process Buffer.", paex);
+            paErrorCode = pae.getErrorCode();
+
+            logger.error("Failed to process Buffer.", pae);
         }
         finally
         {
@@ -688,6 +693,14 @@ public int process(Buffer buffer)
                 streamIsBusy = false;
                 notifyAll();
             }
+
+            /*
+             * If a timeout has occurred in the method Pa.WriteStream, give the
+             * application a little time to allow it to possibly get its act
+             * together.
+             */
+            if (Pa.paTimedOut == paErrorCode)
+                PortAudioStream.yield();
         }
         return BUFFER_PROCESSED_OK;
     }
diff --git a/src/org/jitsi/impl/neomedia/portaudio/Pa.java b/src/org/jitsi/impl/neomedia/portaudio/Pa.java
index 46223bd8..49babcdc 100644
--- a/src/org/jitsi/impl/neomedia/portaudio/Pa.java
+++ b/src/org/jitsi/impl/neomedia/portaudio/Pa.java
@@ -75,11 +75,17 @@ public final class Pa
     public static final int paNoDevice = -1;
 
     /**
-     * The error code defined by the native PortAudio library to signal that no
-     * error is detected/reported.
+     * The <tt>PaErrorCode</tt> value defined by the native PortAudio library to
+     * signal that no error is detected/reported.
      */
     public static final int paNoError = 0;
 
+    /**
+     * The <tt>PaErrorCode</tt> value defined by the native PortAudio library to
+     * signal that a timeout has occurred.
+     */
+    public static final int paTimedOut = -9987;
+
     /**
      * The name of the <tt>double</tt> property which determines the suggested
      * latency to be used when opening PortAudio streams.
-- 
GitLab