aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_audiounit.cpp
diff options
context:
space:
mode:
authorAlex Chronopoulos <[email protected]>2018-10-19 12:16:10 +0200
committerGitHub <[email protected]>2018-10-19 12:16:10 +0200
commitef8f8cb804cdcc602104883f660c4729827479fe (patch)
tree7ebee056cc3c37bb8cc21a6881df62d43ca2f1d0 /src/cubeb_audiounit.cpp
parent5066cfcf4285e44e5e0f7ba8fe3fa4d5d734e2b2 (diff)
downloadcubeb-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.cpp149
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;
}