aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_audiounit.cpp
diff options
context:
space:
mode:
authorChun-Min Chang <[email protected]>2019-10-15 01:40:13 -0700
committerAlex Chronopoulos <[email protected]>2019-10-15 11:40:12 +0300
commitafa02eac12c8a659447be48c129ee9f905e27e93 (patch)
treec8f2b9aa3ee5c5b41569c0d363cf41c7e235587f /src/cubeb_audiounit.cpp
parenta1200c3437419c4c8487df4a065782c7d1b7245f (diff)
downloadcubeb-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.cpp22
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;