Ports Portaudio WMME device timeout system to MacOsX CoreAudio in order to

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
This commit is contained in:
Ross Bencina 2016-09-03 22:53:30 +10:00
commit 66bda13f84
3 changed files with 69 additions and 4 deletions

View 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));
}
}

View file

@ -415,6 +415,10 @@ PaError ReadStream( PaStream* stream,
while( frames > 0 ) {
long avail;
long toRead;
// If PaUtil_GetRingBufferReadAvailable 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;
do {
avail = PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer );
/*
@ -438,6 +442,16 @@ PaError ReadStream( PaStream* stream,
return ret;
#else
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
// 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 += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL;
if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout)
{
return paTimedOut;
}
#endif
}
} while( avail == 0 );
@ -491,6 +505,10 @@ PaError WriteStream( PaStream* stream,
while( frames > 0 ) {
long avail = 0;
long toWrite;
// 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;
do {
avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
@ -515,6 +533,16 @@ PaError WriteStream( PaStream* stream,
return ret;
#else
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
// 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 += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL;
if( PA_COREAUDIO_MAX_TIMEOUT_MSEC_ <= totalTimeout)
{
return paTimedOut;
}
#endif
}
} while( avail == 0 );
@ -561,13 +589,30 @@ PaError WriteStream( PaStream* stream,
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
{
if( blio->outputRingBuffer.buffer ) {
// 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;
long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
while( avail != blio->outputRingBuffer.bufferSize ) {
if( avail == 0 )
{
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
// 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 += PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL;
if( PA_COREAUDIO_MIN_TIMEOUT_MSEC_ <= totalTimeout)
{
return paTimedOut;
}
}
avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
}
}
return paNoError;
}

View file

@ -76,6 +76,9 @@
#define PA_MAC_BLIO_MUTEX
*/
#define PA_COREAUDIO_MIN_TIMEOUT_MSEC_ (1000)
#define PA_COREAUDIO_MAX_TIMEOUT_MSEC_ (2000)
typedef struct {
PaUtilRingBuffer inputRingBuffer;
PaUtilRingBuffer outputRingBuffer;