Mypal/media/libcubeb/uplift-system-listener-patc...

403 lines
13 KiB
Diff

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