]> Repos - portaudio/commitdiff
Ports Portaudio WMME device timeout system to MacOsX CoreAudio in order to jitsi_hotplug
authorRoss Bencina <rossb@audiomulch.com>
Sat, 3 Sep 2016 12:53:30 +0000 (22:53 +1000)
committerRoss Bencina <rossb@audiomulch.com>
Sat, 3 Sep 2016 12:53:30 +0000 (22:53 +1000)
avoid deadlock when a device is unplugged.
Vincent Lucas committed on Jan 10, 2013
2a20693 from https://github.com/jitsi/libsrc/commits/master/portaudio.zip

src/hostapi/coreaudio/pa_mac_core.c
src/hostapi/coreaudio/pa_mac_core_blocking.c
src/hostapi/coreaudio/pa_mac_core_blocking.h

index 25cb2c517fe2c6ab17b9640f6971b228d9ed0f24..08a38aabbffd0bce984fb5f87b15c56282a680c8 100644 (file)
@@ -2460,15 +2460,32 @@ static PaError StartStream( PaStream *s )
 
 // it's not clear from appl's docs that this really waits
 // until all data is flushed.
-static ComponentResult BlockWhileAudioUnitIsRunning( AudioUnit audioUnit, AudioUnitElement element )
+static ComponentResult BlockWhileAudioUnitIsRunning(
+        AudioUnit audioUnit,
+        AudioUnitElement element)
 {
+    long waitTime = 100;
+    // If PaUtil_GetRingBufferWriteAvailable starts repetitively and
+    // consecutively returning that there is no data available, do eventually
+    // give up in order to allow the caller to handle such cases. 
+    long totalTimeout = 0;
     Boolean isRunning = 1;
     while( isRunning ) {
        UInt32 s = sizeof( isRunning );
        ComponentResult err = AudioUnitGetProperty( audioUnit, kAudioOutputUnitProperty_IsRunning, kAudioUnitScope_Global, element,  &isRunning, &s );
        if( err )
           return err;
-       Pa_Sleep( 100 );
+       Pa_Sleep( waitTime );
+
+       // If a timeout is encountered, continue.  However, testing has
+       // shown that it is possible to unplug a device and to wait here
+       // forever. In order to allow the caller to handle such cases of
+       // repeated timeouts, do eventually given up. 
+       totalTimeout += waitTime; 
+       if( PA_COREAUDIO_MIN_TIMEOUT_MSEC_ <= totalTimeout) 
+       {
+           return paTimedOut;
+       } 
     }
     return noErr;
 }
@@ -2481,7 +2498,7 @@ static PaError StopStream( PaStream *s )
     VVDBUG(("StopStream()\n"));
 
     VDBUG( ("Waiting for BLIO.\n") );
-    waitUntilBlioWriteBufferIsFlushed( &stream->blio );
+    waitUntilBlioWriteBufferIsFlushed( &stream->blio);
     VDBUG( ( "Stopping stream.\n" ) );
 
     stream->state = STOPPING;
@@ -2507,7 +2524,7 @@ static PaError StopStream( PaStream *s )
        if( stream->outputUnit )
        {
           ERR_WRAP(AudioOutputUnitStop(stream->outputUnit));
-          ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0) );
+          ERR_WRAP( BlockWhileAudioUnitIsRunning(stream->outputUnit,0));
           ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0));
        }
     }
index 5a98826b62b98fc68548540ba6b9d551917b81ac..c51fd5243ec4dd2352d776009107e49cc32535cc 100644 (file)
@@ -415,6 +415,10 @@ PaError ReadStream( PaStream* stream,
     while( frames > 0 ) {\r
        long avail;\r
        long toRead;\r
+       // If PaUtil_GetRingBufferReadAvailable starts repetitively and\r
+       // consecutively returning that there is no data available, do eventually\r
+       // give up in order to allow the caller to handle such cases. \r
+       long totalTimeout = 0;\r
        do {\r
           avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );\r
 /*\r
@@ -438,6 +442,16 @@ PaError ReadStream( PaStream* stream,
                 return ret;\r
 #else\r
              Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );\r
+\r
+             // If a timeout is encountered, continue.  However, testing has\r
+             // shown that it is possible to unplug a device and to wait here\r
+             // forever. In order to allow the caller to handle such cases of\r
+             // repeated timeouts, do eventually given up. \r
+             totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; \r
+             if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout) \r
+             {\r
+                 return paTimedOut;\r
+             } \r
 #endif\r
           }\r
        } while( avail == 0 );\r
@@ -491,6 +505,10 @@ PaError WriteStream( PaStream* stream,
     while( frames > 0 ) {\r
        long avail = 0;\r
        long toWrite;\r
+       // If PaUtil_GetRingBufferWriteAvailable starts repetitively and\r
+       // consecutively returning that there is no data available, do eventually\r
+       // give up in order to allow the caller to handle such cases. \r
+       long totalTimeout = 0;\r
 \r
        do {\r
           avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );\r
@@ -515,6 +533,16 @@ PaError WriteStream( PaStream* stream,
                 return ret;\r
 #else\r
              Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );\r
+\r
+             // If a timeout is encountered, continue.  However, testing has\r
+             // shown that it is possible to unplug a device and to wait here\r
+             // forever. In order to allow the caller to handle such cases of\r
+             // repeated timeouts, do eventually given up. \r
+             totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; \r
+             if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout) \r
+             {\r
+                 return paTimedOut;\r
+             } \r
 #endif\r
           }\r
        } while( avail == 0 );\r
@@ -561,13 +589,30 @@ PaError WriteStream( PaStream* stream,
 void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )\r
 {\r
     if( blio->outputRingBuffer.buffer ) {\r
+       // If PaUtil_GetRingBufferWriteAvailable starts repetitively and\r
+       // consecutively returning that there is no data available, do eventually\r
+       // give up in order to allow the caller to handle such cases. \r
+       long totalTimeout = 0;\r
        long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );\r
        while( avail != blio->outputRingBuffer.bufferSize ) {\r
           if( avail == 0 )\r
+          {\r
              Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );\r
+\r
+             // If a timeout is encountered, continue.  However, testing has\r
+             // shown that it is possible to unplug a device and to wait here\r
+             // forever. In order to allow the caller to handle such cases of\r
+             // repeated timeouts, do eventually given up. \r
+             totalTimeout += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL; \r
+             if( PA_COREAUDIO_MIN_TIMEOUT_MSEC_ <= totalTimeout) \r
+             {\r
+                 return paTimedOut;\r
+             } \r
+          }\r
           avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );\r
        }\r
     }\r
+    return paNoError;\r
 }\r
 \r
 \r
index 971223b3cf9a181dd430839d8589ab83b4366f82..690a5e21dcc99cfd864c38e87b40e0c8f71145cc 100644 (file)
@@ -76,6 +76,9 @@
 #define PA_MAC_BLIO_MUTEX\r
 */\r
 \r
+#define PA_COREAUDIO_MIN_TIMEOUT_MSEC_ (1000)\r
+#define PA_COREAUDIO_MAX_TIMEOUT_MSEC_ (2000)\r
+\r
 typedef struct {\r
     PaUtilRingBuffer inputRingBuffer;\r
     PaUtilRingBuffer outputRingBuffer;\r