Skip to content

Commit 6174084

Browse files
committed
Avoid forming deadlock when steam drains upon device switching
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.
1 parent 0b5b52d commit 6174084

1 file changed

Lines changed: 12 additions & 10 deletions

File tree

src/cubeb_audiounit.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,17 @@ audiounit_input_callback(void * user_ptr,
503503
return noErr;
504504
}
505505

506+
if (stm->draining) {
507+
OSStatus r = AudioOutputUnitStop(stm->input_unit);
508+
assert(r == 0);
509+
// Only fire state callback in input-only stream. For duplex stream,
510+
// the state callback will be fired in output callback.
511+
if (stm->output_unit == NULL) {
512+
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
513+
}
514+
return noErr;
515+
}
516+
506517
OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames);
507518
if (r != noErr) {
508519
return r;
@@ -522,12 +533,7 @@ audiounit_input_callback(void * user_ptr,
522533
&total_input_frames,
523534
NULL,
524535
0);
525-
if (outframes < total_input_frames) {
526-
OSStatus r = AudioOutputUnitStop(stm->input_unit);
527-
assert(r == 0);
528-
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
529-
return noErr;
530-
}
536+
stm->draining = outframes < total_input_frames;
531537

532538
// Reset input buffer
533539
stm->input_linear_buffer->clear();
@@ -614,10 +620,6 @@ audiounit_output_callback(void * user_ptr,
614620
if (stm->draining) {
615621
OSStatus r = AudioOutputUnitStop(stm->output_unit);
616622
assert(r == 0);
617-
if (stm->input_unit) {
618-
r = AudioOutputUnitStop(stm->input_unit);
619-
assert(r == 0);
620-
}
621623
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
622624
audiounit_make_silent(&outBufferList->mBuffers[0]);
623625
return noErr;

0 commit comments

Comments
 (0)