diff options
Diffstat (limited to 'media/libcubeb/uplift-system-listener-patch.patch')
-rw-r--r-- | media/libcubeb/uplift-system-listener-patch.patch | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/media/libcubeb/uplift-system-listener-patch.patch b/media/libcubeb/uplift-system-listener-patch.patch new file mode 100644 index 000000000..5064d7fb3 --- /dev/null +++ b/media/libcubeb/uplift-system-listener-patch.patch @@ -0,0 +1,402 @@ +diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp +--- a/media/libcubeb/src/cubeb_audiounit.cpp ++++ b/media/libcubeb/src/cubeb_audiounit.cpp +@@ -594,20 +594,20 @@ audiounit_get_input_device_id(AudioDevic + + return CUBEB_OK; + } + + static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume); + static int audiounit_stream_set_volume(cubeb_stream * stm, float volume); + + static int +-audiounit_reinit_stream(cubeb_stream * stm, bool is_started) ++audiounit_reinit_stream(cubeb_stream * stm) + { + auto_lock context_lock(stm->context->mutex); +- if (is_started) { ++ if (!stm->shutdown) { + audiounit_stream_stop_internal(stm); + } + + { + auto_lock lock(stm->mutex); + float volume = 0.0; + int vol_rv = audiounit_stream_get_volume(stm, &volume); + +@@ -622,32 +622,30 @@ audiounit_reinit_stream(cubeb_stream * s + audiounit_stream_set_volume(stm, volume); + } + + // Reset input frames to force new stream pre-buffer + // silence if needed, check `is_extra_input_needed()` + stm->frames_read = 0; + + // If the stream was running, start it again. +- if (is_started) { ++ if (!stm->shutdown) { + audiounit_stream_start_internal(stm); + } + } + return CUBEB_OK; + } + + static OSStatus + audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count, + const AudioObjectPropertyAddress * addresses, + void * user) + { + cubeb_stream * stm = (cubeb_stream*) user; + stm->switching_device = true; +- // Note if the stream was running or not +- bool was_running = !stm->shutdown; + + LOG("(%p) Audio device changed, %d events.", stm, address_count); + for (UInt32 i = 0; i < address_count; i++) { + switch(addresses[i].mSelector) { + case kAudioHardwarePropertyDefaultOutputDevice: { + LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i); + // Allow restart to choose the new default + stm->output_device = nullptr; +@@ -666,19 +664,20 @@ audiounit_property_listener_callback(Aud + if (stm->is_default_input) { + LOG("It's the default input device, ignore the event"); + return noErr; + } + // Allow restart to choose the new default. Event register only for input. + stm->input_device = nullptr; + } + break; +- case kAudioDevicePropertyDataSource: +- LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i); +- break; ++ case kAudioDevicePropertyDataSource: { ++ LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i); ++ return noErr; ++ } + } + } + + for (UInt32 i = 0; i < address_count; i++) { + switch(addresses[i].mSelector) { + case kAudioHardwarePropertyDefaultOutputDevice: + case kAudioHardwarePropertyDefaultInputDevice: + case kAudioDevicePropertyDeviceIsAlive: +@@ -691,17 +690,17 @@ audiounit_property_listener_callback(Aud + break; + } + } + } + + // Use a new thread, through the queue, to avoid deadlock when calling + // Get/SetProperties method from inside notify callback + dispatch_async(stm->context->serial_queue, ^() { +- if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) { ++ if (audiounit_reinit_stream(stm) != CUBEB_OK) { + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); + LOG("(%p) Could not reopen the stream after switching.", stm); + } + stm->switching_device = false; + }); + + return noErr; + } +@@ -752,27 +751,16 @@ audiounit_install_device_changed_callbac + } + + r = audiounit_add_listener(stm, output_dev_id, kAudioDevicePropertyDataSource, + kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback); + if (r != noErr) { + PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r); + return CUBEB_ERROR; + } +- +- /* This event will notify us when the default audio device changes, +- * for example when the user plugs in a USB headset and the system chooses it +- * automatically as the default, or when another device is chosen in the +- * dropdown list. */ +- r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice, +- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); +- if (r != noErr) { +- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r); +- return CUBEB_ERROR; +- } + } + + if (stm->input_unit) { + /* This event will notify us when the data source on the input device changes. */ + AudioDeviceID input_dev_id; + r = audiounit_get_input_device_id(&input_dev_id); + if (r != noErr) { + return CUBEB_ERROR; +@@ -780,78 +768,112 @@ audiounit_install_device_changed_callbac + + r = audiounit_add_listener(stm, input_dev_id, kAudioDevicePropertyDataSource, + kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback); + if (r != noErr) { + PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource", r); + return CUBEB_ERROR; + } + +- /* This event will notify us when the default input device changes. */ +- r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice, +- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); +- if (r != noErr) { +- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r); +- return CUBEB_ERROR; +- } +- + /* Event to notify when the input is going away. */ + AudioDeviceID dev = stm->input_device ? reinterpret_cast<intptr_t>(stm->input_device) : + audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT); + r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive, + kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); + if (r != noErr) { + PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r); + return CUBEB_ERROR; + } + } + + return CUBEB_OK; + } + + static int ++audiounit_install_system_changed_callback(cubeb_stream * stm) ++{ ++ OSStatus r; ++ ++ if (stm->output_unit) { ++ /* This event will notify us when the default audio device changes, ++ * for example when the user plugs in a USB headset and the system chooses it ++ * automatically as the default, or when another device is chosen in the ++ * dropdown list. */ ++ r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice, ++ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); ++ if (r != noErr) { ++ LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r); ++ return CUBEB_ERROR; ++ } ++ } ++ ++ if (stm->input_unit) { ++ /* This event will notify us when the default input device changes. */ ++ r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice, ++ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); ++ if (r != noErr) { ++ LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r); ++ return CUBEB_ERROR; ++ } ++ } ++ ++ return CUBEB_OK; ++} ++ ++static int + audiounit_uninstall_device_changed_callback(cubeb_stream * stm) + { + OSStatus r; + + if (stm->output_unit) { + AudioDeviceID output_dev_id; + r = audiounit_get_output_device_id(&output_dev_id); + if (r != noErr) { + return CUBEB_ERROR; + } + + r = audiounit_remove_listener(stm, output_dev_id, kAudioDevicePropertyDataSource, + kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback); + if (r != noErr) { + return CUBEB_ERROR; + } +- +- r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice, +- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); +- if (r != noErr) { +- return CUBEB_ERROR; +- } + } + + if (stm->input_unit) { + AudioDeviceID input_dev_id; + r = audiounit_get_input_device_id(&input_dev_id); + if (r != noErr) { + return CUBEB_ERROR; + } + + r = audiounit_remove_listener(stm, input_dev_id, kAudioDevicePropertyDataSource, + kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback); + if (r != noErr) { + return CUBEB_ERROR; + } +- ++ } ++ return CUBEB_OK; ++} ++ ++static int ++audiounit_uninstall_system_changed_callback(cubeb_stream * stm) ++{ ++ OSStatus r; ++ ++ if (stm->output_unit) { ++ r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice, ++ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); ++ if (r != noErr) { ++ return CUBEB_ERROR; ++ } ++ } ++ ++ if (stm->input_unit) { + r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice, +- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); ++ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback); + if (r != noErr) { + return CUBEB_ERROR; + } + } + return CUBEB_OK; + } + + /* Get the acceptable buffer size (in frames) that this device can work with. */ +@@ -1764,16 +1786,22 @@ audiounit_setup_stream(cubeb_stream * st + + if (stm->input_unit && stm->output_unit) { + // According to the I/O hardware rate it is expected a specific pattern of callbacks + // for example is input is 44100 and output is 48000 we expected no more than 2 + // out callback in a row. + stm->expected_output_callbacks_in_a_row = ceilf(stm->output_hw_rate / stm->input_hw_rate); + } + ++ r = audiounit_install_device_changed_callback(stm); ++ if (r != CUBEB_OK) { ++ LOG("(%p) Could not install the device change callback.", stm); ++ return r; ++ } ++ + return CUBEB_OK; + } + + static int + audiounit_stream_init(cubeb * context, + cubeb_stream ** stream, + char const * /* stream_name */, + cubeb_devid input_device, +@@ -1838,31 +1866,37 @@ audiounit_stream_init(cubeb * context, + } + + if (r != CUBEB_OK) { + LOG("(%p) Could not setup the audiounit stream.", stm); + audiounit_stream_destroy(stm); + return r; + } + +- r = audiounit_install_device_changed_callback(stm); ++ r = audiounit_install_system_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not install the device change callback.", stm); + return r; + } + + *stream = stm; + LOG("Cubeb stream (%p) init successful.", stm); + return CUBEB_OK; + } + + static void + audiounit_close_stream(cubeb_stream *stm) + { + stm->mutex.assert_current_thread_owns(); ++ ++ int r = audiounit_uninstall_device_changed_callback(stm); ++ if (r != CUBEB_OK) { ++ LOG("(%p) Could not uninstall the device changed callback", stm); ++ } ++ + if (stm->input_unit) { + AudioUnitUninitialize(stm->input_unit); + AudioComponentInstanceDispose(stm->input_unit); + } + + audiounit_destroy_input_linear_buffer(stm); + + if (stm->output_unit) { +@@ -1873,31 +1907,29 @@ audiounit_close_stream(cubeb_stream *stm + cubeb_resampler_destroy(stm->resampler); + } + + static void + audiounit_stream_destroy(cubeb_stream * stm) + { + stm->shutdown = true; + ++ int r = audiounit_uninstall_system_changed_callback(stm); ++ if (r != CUBEB_OK) { ++ LOG("(%p) Could not uninstall the device changed callback", stm); ++ } ++ + auto_lock context_lock(stm->context->mutex); + audiounit_stream_stop_internal(stm); + + { + auto_lock lock(stm->mutex); + audiounit_close_stream(stm); + } + +-#if !TARGET_OS_IPHONE +- int r = audiounit_uninstall_device_changed_callback(stm); +- if (r != CUBEB_OK) { +- LOG("(%p) Could not uninstall the device changed callback", stm); +- } +-#endif +- + assert(stm->context->active_streams >= 1); + stm->context->active_streams -= 1; + + LOG("Cubeb stream (%p) destroyed successful.", stm); + + stm->~cubeb_stream(); + free(stm); + } +@@ -1914,20 +1946,20 @@ audiounit_stream_start_internal(cubeb_st + r = AudioOutputUnitStart(stm->output_unit); + assert(r == 0); + } + } + + static int + audiounit_stream_start(cubeb_stream * stm) + { ++ auto_lock context_lock(stm->context->mutex); + stm->shutdown = false; + stm->draining = false; + +- auto_lock context_lock(stm->context->mutex); + audiounit_stream_start_internal(stm); + + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); + + LOG("Cubeb stream (%p) started successfully.", stm); + return CUBEB_OK; + } + +@@ -1943,19 +1975,19 @@ audiounit_stream_stop_internal(cubeb_str + r = AudioOutputUnitStop(stm->output_unit); + assert(r == 0); + } + } + + static int + audiounit_stream_stop(cubeb_stream * stm) + { ++ auto_lock context_lock(stm->context->mutex); + stm->shutdown = true; + +- auto_lock context_lock(stm->context->mutex); + audiounit_stream_stop_internal(stm); + + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); + + LOG("Cubeb stream (%p) stopped successfully.", stm); + return CUBEB_OK; + } + |