diff options
author | Chun-Min Chang <[email protected]> | 2019-10-15 01:40:13 -0700 |
---|---|---|
committer | Alex Chronopoulos <[email protected]> | 2019-10-15 11:40:12 +0300 |
commit | afa02eac12c8a659447be48c129ee9f905e27e93 (patch) | |
tree | c8f2b9aa3ee5c5b41569c0d363cf41c7e235587f /src/cubeb_audiounit.cpp | |
parent | a1200c3437419c4c8487df4a065782c7d1b7245f (diff) | |
download | cubeb-afa02eac12c8a659447be48c129ee9f905e27e93.tar.gz cubeb-afa02eac12c8a659447be48c129ee9f905e27e93.zip |
Avoid forming deadlock when steam drains upon device switching (#528)
This solves the deadlock mentioned in BMO 1572273 comment 6. It's very
likely to have a deadlock when the output callback tries to stop the
input AudioUnit when the input device is unplugged while the output
device is unchanged during a WebRTC call.
One of the thread forming the deadlock is internal so we don't have any
control on it. The only way to free the deadlock is to prevent the
output callback to require the CAMutex tied to the input AudioUnit.
With the change, the input AudioUnit will be stopped in its own callback
so the deadlock won't be formed.
Diffstat (limited to 'src/cubeb_audiounit.cpp')
-rw-r--r-- | src/cubeb_audiounit.cpp | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp index e0c8fc6..4e89a7d 100644 --- a/src/cubeb_audiounit.cpp +++ b/src/cubeb_audiounit.cpp @@ -501,6 +501,17 @@ audiounit_input_callback(void * user_ptr, return noErr; } + if (stm->draining) { + OSStatus r = AudioOutputUnitStop(stm->input_unit); + assert(r == 0); + // Only fire state callback in input-only stream. For duplex stream, + // the state callback will be fired in output callback. + if (stm->output_unit == NULL) { + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); + } + return noErr; + } + OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames); if (r != noErr) { return r; @@ -520,12 +531,7 @@ audiounit_input_callback(void * user_ptr, &total_input_frames, NULL, 0); - if (outframes < total_input_frames) { - OSStatus r = AudioOutputUnitStop(stm->input_unit); - assert(r == 0); - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); - return noErr; - } + stm->draining = outframes < total_input_frames; // Reset input buffer stm->input_linear_buffer->clear(); @@ -612,10 +618,6 @@ audiounit_output_callback(void * user_ptr, if (stm->draining) { OSStatus r = AudioOutputUnitStop(stm->output_unit); assert(r == 0); - if (stm->input_unit) { - r = AudioOutputUnitStop(stm->input_unit); - assert(r == 0); - } stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); audiounit_make_silent(&outBufferList->mBuffers[0]); return noErr; |