diff options
author | Alex Chronopoulos <[email protected]> | 2018-10-19 12:16:10 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2018-10-19 12:16:10 +0200 |
commit | ef8f8cb804cdcc602104883f660c4729827479fe (patch) | |
tree | 7ebee056cc3c37bb8cc21a6881df62d43ca2f1d0 /src/cubeb_audiounit.cpp | |
parent | 5066cfcf4285e44e5e0f7ba8fe3fa4d5d734e2b2 (diff) | |
download | cubeb-ef8f8cb804cdcc602104883f660c4729827479fe.tar.gz cubeb-ef8f8cb804cdcc602104883f660c4729827479fe.zip |
audiounit: separate input output callbacks for collection changes (BMO 1498242) (#465)
* audiounit: separate input output callbacks for collection changes (BMO 1498242)
* Apply review comments so far
* More review comments
Diffstat (limited to 'src/cubeb_audiounit.cpp')
-rw-r--r-- | src/cubeb_audiounit.cpp | 149 |
1 files changed, 91 insertions, 58 deletions
diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp index 9c6d828..528778a 100644 --- a/src/cubeb_audiounit.cpp +++ b/src/cubeb_audiounit.cpp @@ -132,11 +132,13 @@ struct cubeb { owned_critical_section mutex; int active_streams = 0; uint32_t global_latency_frames = 0; - cubeb_device_collection_changed_callback collection_changed_callback = nullptr; - void * collection_changed_user_ptr = nullptr; - /* Differentiate input from output devices. */ - cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN; - vector<AudioObjectID> devtype_device_array; + cubeb_device_collection_changed_callback input_collection_changed_callback = nullptr; + void * input_collection_changed_user_ptr = nullptr; + cubeb_device_collection_changed_callback output_collection_changed_callback = nullptr; + void * output_collection_changed_user_ptr = nullptr; + // Store list of devices to detect changes + vector<AudioObjectID> input_device_array; + vector<AudioObjectID> output_device_array; // The queue is asynchronously deallocated once all references to it are released dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL); // Current used channel layout @@ -1406,7 +1408,7 @@ audiounit_get_current_channel_layout(AudioUnit output_unit) static int audiounit_create_unit(AudioUnit * unit, device_info * device); -static OSStatus audiounit_remove_device_listener(cubeb * context); +static OSStatus audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype); static void audiounit_destroy(cubeb * ctx) @@ -1421,8 +1423,11 @@ audiounit_destroy(cubeb * ctx) } /* Unregister the callback if necessary. */ - if (ctx->collection_changed_callback) { - audiounit_remove_device_listener(ctx); + if (ctx->input_collection_changed_callback) { + audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_INPUT); + } + if (ctx->output_collection_changed_callback) { + audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_OUTPUT); } } @@ -1841,8 +1846,8 @@ audiounit_workaround_for_airpod(cubeb_stream * stm) std::string input_name_str(input_device_info.friendly_name); std::string output_name_str(output_device_info.friendly_name); - if( input_name_str.find("AirPods") != std::string::npos - && output_name_str.find("AirPods") != std::string::npos ) { + if(input_name_str.find("AirPods") != std::string::npos && + output_name_str.find("AirPods") != std::string::npos) { uint32_t input_min_rate = 0; uint32_t input_max_rate = 0; uint32_t input_nominal_rate = 0; @@ -1980,8 +1985,8 @@ audiounit_new_unit_instance(AudioUnit * unit, device_info * device) // so we retain automatic output device switching when the default // changes. Once we have complete support for device notifications // and switching, we can use the AUHAL for everything. - if ((device->flags & DEV_SYSTEM_DEFAULT) - && (device->flags & DEV_OUTPUT)) { + if ((device->flags & DEV_SYSTEM_DEFAULT) && + (device->flags & DEV_OUTPUT)) { desc.componentSubType = kAudioUnitSubType_DefaultOutput; } else { desc.componentSubType = kAudioUnitSubType_HALOutput; @@ -2041,8 +2046,8 @@ audiounit_create_unit(AudioUnit * unit, device_info * device) } assert(*unit); - if ((device->flags & DEV_SYSTEM_DEFAULT) - && (device->flags & DEV_OUTPUT)) { + if ((device->flags & DEV_SYSTEM_DEFAULT) && + (device->flags & DEV_OUTPUT)) { return CUBEB_OK; } @@ -3450,23 +3455,27 @@ audiounit_collection_changed_callback(AudioObjectID /* inObjectID */, // This can be called from inside an AudioUnit function, dispatch to another queue. dispatch_async(context->serial_queue, ^() { auto_lock lock(context->mutex); - if (context->collection_changed_callback == NULL) { + if (!context->input_collection_changed_callback && + !context->output_collection_changed_callback) { /* Listener removed while waiting in mutex, abort. */ return; } - - assert(context->collection_changed_devtype & - (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)); - - vector<AudioObjectID> devices = audiounit_get_devices_of_type(context->collection_changed_devtype); - /* The elements in the vector are sorted. */ - if (context->devtype_device_array == devices) { - /* Device changed for the other scope, ignore. */ - return; + if (context->input_collection_changed_callback) { + vector<AudioObjectID> devices = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_INPUT); + /* Elements in the vector expected sorted. */ + if (context->input_device_array != devices) { + context->input_device_array = devices; + context->input_collection_changed_callback(context, context->input_collection_changed_user_ptr); + } + } + if (context->output_collection_changed_callback) { + vector<AudioObjectID> devices = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_OUTPUT); + /* Elements in the vector expected sorted. */ + if (context->output_device_array != devices) { + context->output_device_array = devices; + context->output_collection_changed_callback(context, context->output_collection_changed_user_ptr); + } } - /* Device on desired scope has changed. */ - context->devtype_device_array = devices; - context->collection_changed_callback(context, context->collection_changed_user_ptr); }); return noErr; } @@ -3477,45 +3486,65 @@ audiounit_add_device_listener(cubeb * context, cubeb_device_collection_changed_callback collection_changed_callback, void * user_ptr) { + context->mutex.assert_current_thread_owns(); + assert(devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)); /* Note: second register without unregister first causes 'nope' error. * Current implementation requires unregister before register a new cb. */ - assert(context->collection_changed_callback == NULL); + assert((devtype & CUBEB_DEVICE_TYPE_INPUT) && !context->input_collection_changed_callback || + (devtype & CUBEB_DEVICE_TYPE_OUTPUT) && !context->output_collection_changed_callback); - OSStatus ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, - &DEVICES_PROPERTY_ADDRESS, - audiounit_collection_changed_callback, - context); - if (ret == noErr) { + if (!context->input_collection_changed_callback && + !context->output_collection_changed_callback) { + OSStatus ret = AudioObjectAddPropertyListener(kAudioObjectSystemObject, + &DEVICES_PROPERTY_ADDRESS, + audiounit_collection_changed_callback, + context); + if (ret != noErr) { + return ret; + } + } + if (devtype & CUBEB_DEVICE_TYPE_INPUT) { /* Expected empty after unregister. */ - assert(context->devtype_device_array.empty()); - /* Listener works for input and output. - * When requested one of them we need to differentiate. */ - assert(devtype & - (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)); - context->devtype_device_array = audiounit_get_devices_of_type(devtype); - context->collection_changed_devtype = devtype; - context->collection_changed_callback = collection_changed_callback; - context->collection_changed_user_ptr = user_ptr; + assert(context->input_device_array.empty()); + context->input_device_array = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_INPUT); + context->input_collection_changed_callback = collection_changed_callback; + context->input_collection_changed_user_ptr = user_ptr; } - return ret; + if (devtype & CUBEB_DEVICE_TYPE_OUTPUT) { + /* Expected empty after unregister. */ + assert(context->output_device_array.empty()); + context->output_device_array = audiounit_get_devices_of_type(CUBEB_DEVICE_TYPE_OUTPUT); + context->output_collection_changed_callback = collection_changed_callback; + context->output_collection_changed_user_ptr = user_ptr; + } + return noErr; } static OSStatus -audiounit_remove_device_listener(cubeb * context) +audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype) { - /* Note: unregister a non registered cb is not a problem, not checking. */ - OSStatus ret = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, - &DEVICES_PROPERTY_ADDRESS, - audiounit_collection_changed_callback, - context); - if (ret == noErr) { - /* Reset all values. */ - context->collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN; - context->collection_changed_callback = NULL; - context->collection_changed_user_ptr = NULL; - context->devtype_device_array.clear(); + context->mutex.assert_current_thread_owns(); + + if (devtype & CUBEB_DEVICE_TYPE_INPUT) { + context->input_collection_changed_callback = nullptr; + context->input_collection_changed_user_ptr = nullptr; + context->input_device_array.clear(); } - return ret; + if (devtype & CUBEB_DEVICE_TYPE_OUTPUT) { + context->output_collection_changed_callback = nullptr; + context->output_collection_changed_user_ptr = nullptr; + context->output_device_array.clear(); + } + + if (context->input_collection_changed_callback || + context->output_collection_changed_callback) { + return noErr; + } + /* Note: unregister a non registered cb is not a problem, not checking. */ + return AudioObjectRemovePropertyListener(kAudioObjectSystemObject, + &DEVICES_PROPERTY_ADDRESS, + audiounit_collection_changed_callback, + context); } int audiounit_register_device_collection_changed(cubeb * context, @@ -3523,14 +3552,18 @@ int audiounit_register_device_collection_changed(cubeb * context, cubeb_device_collection_changed_callback collection_changed_callback, void * user_ptr) { + if (devtype == CUBEB_DEVICE_TYPE_UNKNOWN) { + return CUBEB_ERROR_INVALID_PARAMETER; + } OSStatus ret; auto_lock lock(context->mutex); if (collection_changed_callback) { - ret = audiounit_add_device_listener(context, devtype, + ret = audiounit_add_device_listener(context, + devtype, collection_changed_callback, user_ptr); } else { - ret = audiounit_remove_device_listener(context); + ret = audiounit_remove_device_listener(context, devtype); } return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR; } |