From da4c7e7ed675c3bf405668739c3012d140856109 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:34:42 +0200 Subject: Adding upstream version 126.0. Signed-off-by: Daniel Baumann --- .../0004-audiounit-ios-compile-fixes.patch | 1415 ++++++++++++++++++++ media/libcubeb/0005-aaudio-timing-fix.patch | 57 + media/libcubeb/moz.yaml | 2 + media/libcubeb/src/cubeb_aaudio.cpp | 2 + media/libcubeb/src/cubeb_audiounit.cpp | 190 ++- media/libcubeb/src/cubeb_triple_buffer.h | 7 + media/libcubeb/src/moz.build | 2 +- media/libcubeb/test/test_triple_buffer.cpp | 3 + 8 files changed, 1635 insertions(+), 43 deletions(-) create mode 100644 media/libcubeb/0004-audiounit-ios-compile-fixes.patch create mode 100644 media/libcubeb/0005-aaudio-timing-fix.patch (limited to 'media/libcubeb') diff --git a/media/libcubeb/0004-audiounit-ios-compile-fixes.patch b/media/libcubeb/0004-audiounit-ios-compile-fixes.patch new file mode 100644 index 0000000000..465ae0f98a --- /dev/null +++ b/media/libcubeb/0004-audiounit-ios-compile-fixes.patch @@ -0,0 +1,1415 @@ +diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp +--- a/src/cubeb_audiounit.cpp ++++ b/src/cubeb_audiounit.cpp +@@ -36,16 +36,25 @@ + #include + + using namespace std; + + #if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 + typedef UInt32 AudioFormatFlags; + #endif + ++#if TARGET_OS_IPHONE ++typedef UInt32 AudioDeviceID; ++typedef UInt32 AudioObjectID; ++const UInt32 kAudioObjectUnknown = 0; ++ ++#define AudioGetCurrentHostTime mach_absolute_time ++ ++#endif ++ + #define AU_OUT_BUS 0 + #define AU_IN_BUS 1 + + const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb"; + const char * PRIVATE_AGGREGATE_DEVICE_NAME = "CubebAggregateDevice"; + + #ifdef ALOGV + #undef ALOGV +@@ -60,45 +69,47 @@ const char * PRIVATE_AGGREGATE_DEVICE_NA + #undef ALOG + #endif + #define ALOG(msg, ...) \ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), \ + ^{ \ + LOG(msg, ##__VA_ARGS__); \ + }) + ++#if !TARGET_OS_IPHONE + /* Testing empirically, some headsets report a minimal latency that is very + * low, but this does not work in practice. Lie and say the minimum is 256 + * frames. */ + const uint32_t SAFE_MIN_LATENCY_FRAMES = 128; + const uint32_t SAFE_MAX_LATENCY_FRAMES = 512; + + const AudioObjectPropertyAddress DEFAULT_INPUT_DEVICE_PROPERTY_ADDRESS = { + kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + const AudioObjectPropertyAddress DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS = { + kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + const AudioObjectPropertyAddress DEVICE_IS_ALIVE_PROPERTY_ADDRESS = { + kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + const AudioObjectPropertyAddress DEVICES_PROPERTY_ADDRESS = { + kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + const AudioObjectPropertyAddress INPUT_DATA_SOURCE_PROPERTY_ADDRESS = { + kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeInput, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + const AudioObjectPropertyAddress OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS = { + kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; ++#endif + + typedef uint32_t device_flags_value; + + enum device_flags { + DEV_UNKNOWN = 0x00, /* Unknown */ + DEV_INPUT = 0x01, /* Record device like mic */ + DEV_OUTPUT = 0x02, /* Playback device like speakers */ + DEV_SYSTEM_DEFAULT = 0x04, /* System default device */ +@@ -109,49 +120,51 @@ enum device_flags { + void + audiounit_stream_stop_internal(cubeb_stream * stm); + static int + audiounit_stream_start_internal(cubeb_stream * stm); + static void + audiounit_close_stream(cubeb_stream * stm); + static int + audiounit_setup_stream(cubeb_stream * stm); ++#if !TARGET_OS_IPHONE + static vector + audiounit_get_devices_of_type(cubeb_device_type devtype); + static UInt32 + audiounit_get_device_presentation_latency(AudioObjectID devid, + AudioObjectPropertyScope scope); +- +-#if !TARGET_OS_IPHONE + static AudioObjectID + audiounit_get_default_device_id(cubeb_device_type type); + static int + audiounit_uninstall_device_changed_callback(cubeb_stream * stm); + static int + audiounit_uninstall_system_changed_callback(cubeb_stream * stm); ++#endif ++ + static void + audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags); +-#endif + + extern cubeb_ops const audiounit_ops; + + struct cubeb { + cubeb_ops const * ops = &audiounit_ops; + owned_critical_section mutex; + int active_streams = 0; + uint32_t global_latency_frames = 0; + 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; ++ #if !TARGET_OS_IPHONE + // Store list of devices to detect changes + vector input_device_array; + vector output_device_array; ++ #endif + // The queue should be released when it’s no longer needed. + dispatch_queue_t serial_queue = + dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL); + // Current used channel layout + atomic layout{CUBEB_LAYOUT_UNDEFINED}; + uint32_t channels = 0; + }; + +@@ -181,29 +194,31 @@ to_string(io_side side) + } + } + + struct device_info { + AudioDeviceID id = kAudioObjectUnknown; + device_flags_value flags = DEV_UNKNOWN; + }; + ++#if !TARGET_OS_IPHONE + struct property_listener { + AudioDeviceID device_id; + const AudioObjectPropertyAddress * property_address; + AudioObjectPropertyListenerProc callback; + cubeb_stream * stream; + + property_listener(AudioDeviceID id, + const AudioObjectPropertyAddress * address, + AudioObjectPropertyListenerProc proc, cubeb_stream * stm) + : device_id(id), property_address(address), callback(proc), stream(stm) + { + } + }; ++#endif + + struct cubeb_stream { + explicit cubeb_stream(cubeb * context); + + /* Note: Must match cubeb_stream layout in cubeb.c. */ + cubeb * context; + void * user_ptr = nullptr; + /**/ +@@ -252,32 +267,36 @@ struct cubeb_stream { + /* Latency requested by the user. */ + uint32_t latency_frames = 0; + atomic current_latency_frames{0}; + atomic total_output_latency_frames{0}; + unique_ptr resampler; + /* This is true if a device change callback is currently running. */ + atomic switching_device{false}; + atomic buffer_size_change_state{false}; ++ #if !TARGET_OS_IPHONE + AudioDeviceID aggregate_device_id = + kAudioObjectUnknown; // the aggregate device id + AudioObjectID plugin_id = + kAudioObjectUnknown; // used to create aggregate device ++ #endif + /* Mixer interface */ + unique_ptr mixer; + /* Buffer where remixing/resampling will occur when upmixing is required */ + /* Only accessed from callback thread */ + unique_ptr temp_buffer; + size_t temp_buffer_size = 0; // size in bytes. ++ #if !TARGET_OS_IPHONE + /* Listeners indicating what system events are monitored. */ + unique_ptr default_input_listener; + unique_ptr default_output_listener; + unique_ptr input_alive_listener; + unique_ptr input_source_listener; + unique_ptr output_source_listener; ++ #endif + }; + + bool + has_input(cubeb_stream * stm) + { + return stm->input_stream_params.rate != 0; + } + +@@ -381,24 +400,16 @@ bool + is_common_sample_rate(Float64 sample_rate) + { + /* Some commonly used sample rates and their multiples and divisors. */ + return sample_rate == 8000 || sample_rate == 16000 || sample_rate == 22050 || + sample_rate == 32000 || sample_rate == 44100 || sample_rate == 48000 || + sample_rate == 88200 || sample_rate == 96000; + } + +-#if TARGET_OS_IPHONE +-typedef UInt32 AudioDeviceID; +-typedef UInt32 AudioObjectID; +- +-#define AudioGetCurrentHostTime mach_absolute_time +- +-#endif +- + uint64_t + ConvertHostTimeToNanos(uint64_t host_time) + { + static struct mach_timebase_info timebase_info; + static bool initialized = false; + if (!initialized) { + mach_timebase_info(&timebase_info); + initialized = true; +@@ -756,23 +767,23 @@ audiounit_init(cubeb ** context, char co + } + + static char const * + audiounit_get_backend_id(cubeb * /* ctx */) + { + return "audiounit"; + } + +-#if !TARGET_OS_IPHONE + + static int + audiounit_stream_get_volume(cubeb_stream * stm, float * volume); + static int + audiounit_stream_set_volume(cubeb_stream * stm, float volume); + ++#if !TARGET_OS_IPHONE + static int + audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side) + { + assert(stm); + + device_info * info = nullptr; + cubeb_device_type type = CUBEB_DEVICE_TYPE_UNKNOWN; + +@@ -806,42 +817,47 @@ audiounit_set_device_info(cubeb_stream * + } + + assert(info->id); + assert(info->flags & DEV_INPUT && !(info->flags & DEV_OUTPUT) || + !(info->flags & DEV_INPUT) && info->flags & DEV_OUTPUT); + + return CUBEB_OK; + } ++#endif + + static int + audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) + { + auto_lock context_lock(stm->context->mutex); + assert((flags & DEV_INPUT && stm->input_unit) || + (flags & DEV_OUTPUT && stm->output_unit)); + if (!stm->shutdown) { + audiounit_stream_stop_internal(stm); + } + +- int r = audiounit_uninstall_device_changed_callback(stm); ++ int r; ++#if !TARGET_OS_IPHONE ++ r = audiounit_uninstall_device_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not uninstall all device change listeners.", stm); + } ++#endif + + { + auto_lock lock(stm->mutex); + float volume = 0.0; + int vol_rv = CUBEB_ERROR; + if (stm->output_unit) { + vol_rv = audiounit_stream_get_volume(stm, &volume); + } + + audiounit_close_stream(stm); + ++ #if !TARGET_OS_IPHONE + /* Reinit occurs in one of the following case: + * - When the device is not alive any more + * - When the default system device change. + * - The bluetooth device changed from A2DP to/from HFP/HSP profile + * We first attempt to re-use the same device id, should that fail we will + * default to the (potentially new) default device. */ + AudioDeviceID input_device = + flags & DEV_INPUT ? stm->input_device.id : kAudioObjectUnknown; +@@ -861,29 +877,33 @@ audiounit_reinit_stream(cubeb_stream * s + r = audiounit_set_device_info(stm, kAudioObjectUnknown, io_side::OUTPUT); + if (r != CUBEB_OK) { + LOG("(%p) Set output device info failed. This can happen when last media " + "device is unplugged", + stm); + return CUBEB_ERROR; + } + ++ #endif ++ + if (audiounit_setup_stream(stm) != CUBEB_OK) { + LOG("(%p) Stream reinit failed.", stm); ++ #if !TARGET_OS_IPHONE + if (flags & DEV_INPUT && input_device != kAudioObjectUnknown) { + // Attempt to re-use the same device-id failed, so attempt again with + // default input device. + audiounit_close_stream(stm); + if (audiounit_set_device_info(stm, kAudioObjectUnknown, + io_side::INPUT) != CUBEB_OK || + audiounit_setup_stream(stm) != CUBEB_OK) { + LOG("(%p) Second stream reinit failed.", stm); + return CUBEB_ERROR; + } + } ++ #endif + } + + if (vol_rv == CUBEB_OK) { + audiounit_stream_set_volume(stm, volume); + } + + // If the stream was running, start it again. + if (!stm->shutdown) { +@@ -909,27 +929,30 @@ audiounit_reinit_stream_async(cubeb_stre + // Get/SetProperties method from inside notify callback + dispatch_async(stm->context->serial_queue, ^() { + if (stm->destroy_pending) { + ALOG("(%p) stream pending destroy, cancelling reinit task", stm); + return; + } + + if (audiounit_reinit_stream(stm, flags) != CUBEB_OK) { ++ #if !TARGET_OS_IPHONE + if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) { + LOG("(%p) Could not uninstall system changed callback", stm); + } ++ #endif + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); + LOG("(%p) Could not reopen the stream after switching.", stm); + } + stm->switching_device = false; + stm->reinit_pending = false; + }); + } + ++#if !TARGET_OS_IPHONE + static char const * + event_addr_to_string(AudioObjectPropertySelector selector) + { + switch (selector) { + case kAudioHardwarePropertyDefaultOutputDevice: + return "kAudioHardwarePropertyDefaultOutputDevice"; + case kAudioHardwarePropertyDefaultInputDevice: + return "kAudioHardwarePropertyDefaultInputDevice"; +@@ -1091,16 +1114,17 @@ audiounit_install_device_changed_callbac + rv, stm->input_device.id); + r = CUBEB_ERROR; + } + } + + return r; + } + ++#if !TARGET_OS_IPHONE + 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 +@@ -1131,16 +1155,17 @@ audiounit_install_system_changed_callbac + "kAudioHardwarePropertyDefaultInputDevice rv=%d", + r); + return CUBEB_ERROR; + } + } + + return CUBEB_OK; + } ++#endif + + static int + audiounit_uninstall_device_changed_callback(cubeb_stream * stm) + { + OSStatus rv; + // Failing to uninstall listeners is not a fatal error. + int r = CUBEB_OK; + +@@ -1207,17 +1232,17 @@ audiounit_uninstall_system_changed_callb + static int + audiounit_get_acceptable_latency_range(AudioValueRange * latency_range) + { + UInt32 size; + OSStatus r; + AudioDeviceID output_device_id; + AudioObjectPropertyAddress output_device_buffer_size_range = { + kAudioDevicePropertyBufferFrameSizeRange, kAudioDevicePropertyScopeOutput, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); + if (output_device_id == kAudioObjectUnknown) { + LOG("Could not get default output device id."); + return CUBEB_ERROR; + } + + /* Get the buffer size range this device supports */ +@@ -1228,17 +1253,16 @@ audiounit_get_acceptable_latency_range(A + &size, latency_range); + if (r != noErr) { + LOG("AudioObjectGetPropertyData/buffer size range rv=%d", r); + return CUBEB_ERROR; + } + + return CUBEB_OK; + } +-#endif /* !TARGET_OS_IPHONE */ + + static AudioObjectID + audiounit_get_default_device_id(cubeb_device_type type) + { + const AudioObjectPropertyAddress * adr; + if (type == CUBEB_DEVICE_TYPE_OUTPUT) { + adr = &DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS; + } else if (type == CUBEB_DEVICE_TYPE_INPUT) { +@@ -1251,31 +1275,32 @@ audiounit_get_default_device_id(cubeb_de + UInt32 size = sizeof(AudioDeviceID); + if (AudioObjectGetPropertyData(kAudioObjectSystemObject, adr, 0, NULL, &size, + &devid) != noErr) { + return kAudioObjectUnknown; + } + + return devid; + } ++#endif /* !TARGET_OS_IPHONE */ + + int + audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) + { + #if TARGET_OS_IPHONE + // TODO: [[AVAudioSession sharedInstance] maximumOutputNumberOfChannels] + *max_channels = 2; + #else + UInt32 size; + OSStatus r; + AudioDeviceID output_device_id; + AudioStreamBasicDescription stream_format; + AudioObjectPropertyAddress stream_format_address = { + kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + assert(ctx && max_channels); + + output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); + if (output_device_id == kAudioObjectUnknown) { + return CUBEB_ERROR; + } + +@@ -1304,52 +1329,52 @@ audiounit_get_min_latency(cubeb * /* ctx + AudioValueRange latency_range; + if (audiounit_get_acceptable_latency_range(&latency_range) != CUBEB_OK) { + LOG("Could not get acceptable latency range."); + return CUBEB_ERROR; + } + + *latency_frames = + max(latency_range.mMinimum, SAFE_MIN_LATENCY_FRAMES); ++ return CUBEB_OK; + #endif +- +- return CUBEB_OK; + } + + static int + audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate) + { + #if TARGET_OS_IPHONE +- // TODO +- return CUBEB_ERROR_NOT_SUPPORTED; ++ *rate = 44100; ++ return CUBEB_OK; + #else + UInt32 size; + OSStatus r; + Float64 fsamplerate; + AudioDeviceID output_device_id; + AudioObjectPropertyAddress samplerate_address = { + kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); + if (output_device_id == kAudioObjectUnknown) { + return CUBEB_ERROR; + } + + size = sizeof(fsamplerate); + r = AudioObjectGetPropertyData(output_device_id, &samplerate_address, 0, NULL, + &size, &fsamplerate); + + if (r != noErr) { + return CUBEB_ERROR; + } + + *rate = static_cast(fsamplerate); ++ ++ return CUBEB_OK; + #endif +- return CUBEB_OK; + } + + static cubeb_channel_layout + audiounit_convert_channel_layout(AudioChannelLayout * layout) + { + // When having one or two channel, force mono or stereo. Some devices (namely, + // Bose QC35, mark 1 and 2), expose a single channel mapped to the right for + // some reason. +@@ -1380,16 +1405,19 @@ audiounit_convert_channel_layout(AudioCh + } + + return cl; + } + + static cubeb_channel_layout + audiounit_get_preferred_channel_layout(AudioUnit output_unit) + { ++ #if TARGET_OS_IPHONE ++ return CUBEB_LAYOUT_STEREO; ++ #else + OSStatus rv = noErr; + UInt32 size = 0; + rv = AudioUnitGetPropertyInfo( + output_unit, kAudioDevicePropertyPreferredChannelLayout, + kAudioUnitScope_Output, AU_OUT_BUS, &size, nullptr); + if (rv != noErr) { + LOG("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout " + "rv=%d", +@@ -1404,16 +1432,17 @@ audiounit_get_preferred_channel_layout(A + kAudioUnitScope_Output, AU_OUT_BUS, layout.get(), &size); + if (rv != noErr) { + LOG("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout rv=%d", + rv); + return CUBEB_LAYOUT_UNDEFINED; + } + + return audiounit_convert_channel_layout(layout.get()); ++ #endif + } + + static cubeb_channel_layout + audiounit_get_current_channel_layout(AudioUnit output_unit) + { + OSStatus rv = noErr; + UInt32 size = 0; + rv = AudioUnitGetPropertyInfo( +@@ -1437,18 +1466,20 @@ audiounit_get_current_channel_layout(Aud + } + + return audiounit_convert_channel_layout(layout.get()); + } + + static int + audiounit_create_unit(AudioUnit * unit, device_info * device); + ++#if !TARGET_OS_IPHONE + static OSStatus + audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype); ++#endif + + static void + audiounit_destroy(cubeb * ctx) + { + { + auto_lock lock(ctx->mutex); + + // Disabling this assert for bug 1083664 -- we seem to leak a stream +@@ -1460,23 +1491,25 @@ audiounit_destroy(cubeb * ctx) + + // Destroying a cubeb context with device collection callbacks registered + // is misuse of the API, assert then attempt to clean up. + assert(!ctx->input_collection_changed_callback && + !ctx->input_collection_changed_user_ptr && + !ctx->output_collection_changed_callback && + !ctx->output_collection_changed_user_ptr); + ++ #if !TARGET_OS_IPHONE + /* Unregister the callback if necessary. */ + 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); + } ++ #endif + } + + dispatch_release(ctx->serial_queue); + + delete ctx; + } + + static void +@@ -1594,23 +1627,24 @@ audiounit_layout_init(cubeb_stream * stm + } + + stm->context->layout = audiounit_get_current_channel_layout(stm->output_unit); + + audiounit_set_channel_layout(stm->output_unit, io_side::OUTPUT, + stm->context->layout); + } + ++#if !TARGET_OS_IPHONE + static vector + audiounit_get_sub_devices(AudioDeviceID device_id) + { + vector sub_devices; + AudioObjectPropertyAddress property_address = { + kAudioAggregateDevicePropertyActiveSubDeviceList, +- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + UInt32 size = 0; + OSStatus rv = AudioObjectGetPropertyDataSize(device_id, &property_address, 0, + nullptr, &size); + + if (rv != noErr) { + sub_devices.push_back(device_id); + return sub_devices; + } +@@ -1629,17 +1663,17 @@ audiounit_get_sub_devices(AudioDeviceID + } + + static int + audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, + AudioDeviceID * aggregate_device_id) + { + AudioObjectPropertyAddress address_plugin_bundle_id = { + kAudioHardwarePropertyPlugInForBundleID, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + UInt32 size = 0; + OSStatus r = AudioObjectGetPropertyDataSize( + kAudioObjectSystemObject, &address_plugin_bundle_id, 0, NULL, &size); + if (r != noErr) { + LOG("AudioObjectGetPropertyDataSize/" + "kAudioHardwarePropertyPlugInForBundleID, rv=%d", + r); + return CUBEB_ERROR; +@@ -1659,17 +1693,17 @@ audiounit_create_blank_aggregate_device( + LOG("AudioObjectGetPropertyData/kAudioHardwarePropertyPlugInForBundleID, " + "rv=%d", + r); + return CUBEB_ERROR; + } + + AudioObjectPropertyAddress create_aggregate_device_address = { + kAudioPlugInCreateAggregateDevice, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + r = AudioObjectGetPropertyDataSize( + *plugin_id, &create_aggregate_device_address, 0, nullptr, &size); + if (r != noErr) { + LOG("AudioObjectGetPropertyDataSize/kAudioPlugInCreateAggregateDevice, " + "rv=%d", + r); + return CUBEB_ERROR; + } +@@ -1731,17 +1765,17 @@ audiounit_create_blank_aggregate_device( + // object is increased. + static CFStringRef + get_device_name(AudioDeviceID id) + { + UInt32 size = sizeof(CFStringRef); + CFStringRef UIname = nullptr; + AudioObjectPropertyAddress address_uuid = {kAudioDevicePropertyDeviceUID, + kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + OSStatus err = + AudioObjectGetPropertyData(id, &address_uuid, 0, nullptr, &size, &UIname); + return (err == noErr) ? UIname : NULL; + } + + static int + audiounit_set_aggregate_sub_device_list(AudioDeviceID aggregate_device_id, + AudioDeviceID input_device_id, +@@ -1774,17 +1808,17 @@ audiounit_set_aggregate_sub_device_list( + return CUBEB_ERROR; + } + CFArrayAppendValue(aggregate_sub_devices_array, ref); + CFRelease(ref); + } + + AudioObjectPropertyAddress aggregate_sub_device_list = { + kAudioAggregateDevicePropertyFullSubDeviceList, +- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + UInt32 size = sizeof(CFMutableArrayRef); + OSStatus rv = AudioObjectSetPropertyData( + aggregate_device_id, &aggregate_sub_device_list, 0, nullptr, size, + &aggregate_sub_devices_array); + CFRelease(aggregate_sub_devices_array); + if (rv != noErr) { + LOG("AudioObjectSetPropertyData/" + "kAudioAggregateDevicePropertyFullSubDeviceList, rv=%d", +@@ -1796,17 +1830,17 @@ audiounit_set_aggregate_sub_device_list( + } + + static int + audiounit_set_master_aggregate_device(const AudioDeviceID aggregate_device_id) + { + assert(aggregate_device_id != kAudioObjectUnknown); + AudioObjectPropertyAddress master_aggregate_sub_device = { + kAudioAggregateDevicePropertyMasterSubDevice, +- kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; + + // Master become the 1st output sub device + AudioDeviceID output_device_id = + audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); + const vector output_sub_devices = + audiounit_get_sub_devices(output_device_id); + CFStringRef master_sub_device = get_device_name(output_sub_devices[0]); + +@@ -1829,17 +1863,17 @@ audiounit_set_master_aggregate_device(co + + static int + audiounit_activate_clock_drift_compensation( + const AudioDeviceID aggregate_device_id) + { + assert(aggregate_device_id != kAudioObjectUnknown); + AudioObjectPropertyAddress address_owned = { + kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + UInt32 qualifier_data_size = sizeof(AudioObjectID); + AudioClassID class_id = kAudioSubDeviceClassID; + void * qualifier_data = &class_id; + UInt32 size = 0; + OSStatus rv = AudioObjectGetPropertyDataSize( + aggregate_device_id, &address_owned, qualifier_data_size, qualifier_data, + &size); +@@ -1861,17 +1895,17 @@ audiounit_activate_clock_drift_compensat + if (rv != noErr) { + LOG("AudioObjectGetPropertyData/kAudioObjectPropertyOwnedObjects, rv=%d", + rv); + return CUBEB_ERROR; + } + + AudioObjectPropertyAddress address_drift = { + kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + // Start from the second device since the first is the master clock + for (UInt32 i = 1; i < subdevices_num; ++i) { + UInt32 drift_compensation_value = 1; + rv = AudioObjectSetPropertyData(sub_devices[i], &address_drift, 0, nullptr, + sizeof(UInt32), &drift_compensation_value); + if (rv != noErr) { + LOG("AudioObjectSetPropertyData/" +@@ -1930,17 +1964,17 @@ audiounit_workaround_for_airpod(cubeb_st + &output_min_rate, &output_max_rate, &output_nominal_rate); + LOG("(%p) Output device %u, name: %s, min: %u, max: %u, nominal rate: %u", + stm, stm->output_device.id, output_device_info.friendly_name, + output_min_rate, output_max_rate, output_nominal_rate); + + Float64 rate = input_nominal_rate; + AudioObjectPropertyAddress addr = {kAudioDevicePropertyNominalSampleRate, + kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + OSStatus rv = AudioObjectSetPropertyData(stm->aggregate_device_id, &addr, 0, + nullptr, sizeof(Float64), &rate); + if (rv != noErr) { + LOG("Non fatal error, " + "AudioObjectSetPropertyData/kAudioDevicePropertyNominalSampleRate, " + "rv=%d", + rv); +@@ -2014,17 +2048,17 @@ audiounit_create_aggregate_device(cubeb_ + static int + audiounit_destroy_aggregate_device(AudioObjectID plugin_id, + AudioDeviceID * aggregate_device_id) + { + assert(aggregate_device_id && *aggregate_device_id != kAudioDeviceUnknown && + plugin_id != kAudioObjectUnknown); + AudioObjectPropertyAddress destroy_aggregate_device_addr = { + kAudioPlugInDestroyAggregateDevice, kAudioObjectPropertyScopeGlobal, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + UInt32 size; + OSStatus rv = AudioObjectGetPropertyDataSize( + plugin_id, &destroy_aggregate_device_addr, 0, NULL, &size); + if (rv != noErr) { + LOG("AudioObjectGetPropertyDataSize/kAudioPlugInDestroyAggregateDevice, " + "rv=%d", + rv); + return CUBEB_ERROR; +@@ -2037,16 +2071,17 @@ audiounit_destroy_aggregate_device(Audio + rv); + return CUBEB_ERROR; + } + + LOG("Destroyed aggregate device %d", *aggregate_device_id); + *aggregate_device_id = kAudioObjectUnknown; + return CUBEB_OK; + } ++#endif + + static int + audiounit_new_unit_instance(AudioUnit * unit, device_info * device) + { + AudioComponentDescription desc; + AudioComponent comp; + OSStatus rv; + +@@ -2173,16 +2208,19 @@ audiounit_init_input_linear_buffer(cubeb + assert(stream->input_linear_buffer->length() == 0); + + return CUBEB_OK; + } + + static uint32_t + audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames) + { ++ #if TARGET_OS_IPHONE ++ return latency_frames; ++ #else + // For the 1st stream set anything within safe min-max + assert(audiounit_active_streams(stm->context) > 0); + if (audiounit_active_streams(stm->context) == 1) { + return max(min(latency_frames, SAFE_MAX_LATENCY_FRAMES), + SAFE_MIN_LATENCY_FRAMES); + } + assert(stm->output_unit); + +@@ -2233,18 +2271,20 @@ audiounit_clamp_latency(cubeb_stream * s + } else if (output_buffer_size != 0) { + upper_latency_limit = output_buffer_size; + } else { + upper_latency_limit = SAFE_MAX_LATENCY_FRAMES; + } + + return max(min(latency_frames, upper_latency_limit), + SAFE_MIN_LATENCY_FRAMES); ++ #endif + } + ++#if !TARGET_OS_IPHONE + /* + * Change buffer size is prone to deadlock thus we change it + * following the steps: + * - register a listener for the buffer size property + * - change the property + * - wait until the listener is executed + * - property has changed, remove the listener + * */ +@@ -2285,21 +2325,25 @@ buffer_size_changed_callback(void * inCl + "= %d for scope %d", + stm, au_type, new_buffer_size, inScope); + } + stm->buffer_size_change_state = true; + break; + } + } + } ++#endif + + static int + audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, + io_side side) + { ++ #if TARGET_OS_IPHONE ++ return CUBEB_OK; ++ #else + AudioUnit au = stm->output_unit; + AudioUnitScope au_scope = kAudioUnitScope_Input; + AudioUnitElement au_element = AU_OUT_BUS; + + if (side == io_side::INPUT) { + au = stm->input_unit; + au_scope = kAudioUnitScope_Output; + au_element = AU_IN_BUS; +@@ -2377,16 +2421,17 @@ audiounit_set_buffer_size(cubeb_stream * + if (!stm->buffer_size_change_state && count >= 30) { + LOG("(%p) Error, did not get buffer size change callback ...", stm); + return CUBEB_ERROR; + } + + LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side), + new_size_frames); + return CUBEB_OK; ++ #endif + } + + static int + audiounit_configure_input(cubeb_stream * stm) + { + assert(stm && stm->input_unit); + + int r = 0; +@@ -2593,16 +2638,17 @@ audiounit_setup_stream(cubeb_stream * st + return CUBEB_ERROR_NOT_SUPPORTED; + } + + int r = 0; + + device_info in_dev_info = stm->input_device; + device_info out_dev_info = stm->output_device; + ++ #if !TARGET_OS_IPHONE + if (has_input(stm) && has_output(stm) && + stm->input_device.id != stm->output_device.id) { + r = audiounit_create_aggregate_device(stm); + if (r != CUBEB_OK) { + stm->aggregate_device_id = kAudioObjectUnknown; + LOG("(%p) Create aggregate devices failed.", stm); + // !!!NOTE: It is not necessary to return here. If it does not + // return it will fallback to the old implementation. The intention +@@ -2610,16 +2656,20 @@ audiounit_setup_stream(cubeb_stream * st + // it after a couple of weeks. + return r; + } else { + in_dev_info.id = out_dev_info.id = stm->aggregate_device_id; + in_dev_info.flags = DEV_INPUT; + out_dev_info.flags = DEV_OUTPUT; + } + } ++ #else ++ in_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_INPUT; ++ out_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_OUTPUT; ++ #endif + + if (has_input(stm)) { + r = audiounit_create_unit(&stm->input_unit, &in_dev_info); + if (r != CUBEB_OK) { + LOG("(%p) AudioUnit creation for input failed.", stm); + return r; + } + } +@@ -2751,18 +2801,20 @@ audiounit_setup_stream(cubeb_stream * st + + if (stm->output_unit != NULL) { + r = AudioUnitInitialize(stm->output_unit); + if (r != noErr) { + LOG("AudioUnitInitialize/output rv=%d", r); + return CUBEB_ERROR; + } + ++ #if !TARGET_OS_IPHONE + stm->current_latency_frames = audiounit_get_device_presentation_latency( + stm->output_device.id, kAudioDevicePropertyScopeOutput); ++ #endif + + Float64 unit_s; + UInt32 size = sizeof(unit_s); + if (AudioUnitGetProperty(stm->output_unit, kAudioUnitProperty_Latency, + kAudioUnitScope_Global, 0, &unit_s, + &size) == noErr) { + stm->current_latency_frames += + static_cast(unit_s * stm->output_desc.mSampleRate); +@@ -2772,20 +2824,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); + } + ++ #if !TARGET_OS_IPHONE + r = audiounit_install_device_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not install all device change callback.", stm); + } ++ #endif + + return CUBEB_OK; + } + + cubeb_stream::cubeb_stream(cubeb * context) + : context(context), resampler(nullptr, cubeb_resampler_destroy), + mixer(nullptr, cubeb_mixer_destroy) + { +@@ -2823,51 +2877,57 @@ audiounit_stream_init(cubeb * context, c + stm->latency_frames = latency_frames; + + if ((input_device && !input_stream_params) || + (output_device && !output_stream_params)) { + return CUBEB_ERROR_INVALID_PARAMETER; + } + if (input_stream_params) { + stm->input_stream_params = *input_stream_params; ++ #if !TARGET_OS_IPHONE + r = audiounit_set_device_info( + stm.get(), reinterpret_cast(input_device), io_side::INPUT); + if (r != CUBEB_OK) { + LOG("(%p) Fail to set device info for input.", stm.get()); + return r; + } ++ #endif + } + if (output_stream_params) { + stm->output_stream_params = *output_stream_params; ++ #if !TARGET_OS_IPHONE + r = audiounit_set_device_info( + stm.get(), reinterpret_cast(output_device), io_side::OUTPUT); + if (r != CUBEB_OK) { + LOG("(%p) Fail to set device info for output.", stm.get()); + return r; + } ++ #endif + } + + { + // It's not critical to lock here, because no other thread has been started + // yet, but it allows to assert that the lock has been taken in + // `audiounit_setup_stream`. + auto_lock lock(stm->mutex); + r = audiounit_setup_stream(stm.get()); + } + + if (r != CUBEB_OK) { + LOG("(%p) Could not setup the audiounit stream.", stm.get()); + return r; + } + ++ #if !TARGET_OS_IPHONE + r = audiounit_install_system_changed_callback(stm.get()); + if (r != CUBEB_OK) { + LOG("(%p) Could not install the device change callback.", stm.get()); + return r; + } ++ #endif + + *stream = stm.release(); + LOG("(%p) Cubeb stream init successful.", *stream); + return CUBEB_OK; + } + + static void + audiounit_close_stream(cubeb_stream * stm) +@@ -2886,54 +2946,60 @@ audiounit_close_stream(cubeb_stream * st + AudioUnitUninitialize(stm->output_unit); + AudioComponentInstanceDispose(stm->output_unit); + stm->output_unit = nullptr; + } + + stm->resampler.reset(); + stm->mixer.reset(); + ++ #if !TARGET_OS_IPHONE + if (stm->aggregate_device_id != kAudioObjectUnknown) { + audiounit_destroy_aggregate_device(stm->plugin_id, + &stm->aggregate_device_id); + stm->aggregate_device_id = kAudioObjectUnknown; + } ++ #endif + } + + static void + audiounit_stream_destroy_internal(cubeb_stream * stm) + { + stm->context->mutex.assert_current_thread_owns(); + ++#if !TARGET_OS_IPHONE + int r = audiounit_uninstall_system_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not uninstall the device changed callback", stm); + } + r = audiounit_uninstall_device_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not uninstall all device change listeners", stm); + } ++#endif + + auto_lock lock(stm->mutex); + audiounit_close_stream(stm); + assert(audiounit_active_streams(stm->context) >= 1); + audiounit_decrement_active_streams(stm->context); + } + + static void + audiounit_stream_destroy(cubeb_stream * stm) + { ++ #if !TARGET_OS_IPHONE + int r = audiounit_uninstall_system_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not uninstall the device changed callback", stm); + } + r = audiounit_uninstall_device_changed_callback(stm); + if (r != CUBEB_OK) { + LOG("(%p) Could not uninstall all device change listeners", stm); + } ++ #endif + + if (!stm->shutdown.load()) { + auto_lock context_lock(stm->context->mutex); + audiounit_stream_stop_internal(stm); + stm->shutdown = true; + } + + stm->destroy_pending = true; +@@ -3081,16 +3147,17 @@ convert_uint32_into_string(UInt32 data) + // Reverse 0xWXYZ into 0xZYXW. + str[0] = (char)(data >> 24); + str[1] = (char)(data >> 16); + str[2] = (char)(data >> 8); + str[3] = (char)(data); + return str; + } + ++#if !TARGET_OS_IPHONE + int + audiounit_get_default_device_datasource(cubeb_device_type type, UInt32 * data) + { + AudioDeviceID id = audiounit_get_default_device_id(type); + if (id == kAudioObjectUnknown) { + return CUBEB_ERROR; + } + +@@ -3102,38 +3169,43 @@ audiounit_get_default_device_datasource( + : &OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS, + 0, NULL, &size, data); + if (r != noErr) { + *data = 0; + } + + return CUBEB_OK; + } ++#endif + + int + audiounit_get_default_device_name(cubeb_stream * stm, + cubeb_device * const device, + cubeb_device_type type) + { ++#if TARGET_OS_IPHONE ++ return CUBEB_ERROR_NOT_SUPPORTED; ++#else + assert(stm); + assert(device); + + UInt32 data; + int r = audiounit_get_default_device_datasource(type, &data); + if (r != CUBEB_OK) { + return r; + } + char ** name = type == CUBEB_DEVICE_TYPE_INPUT ? &device->input_name + : &device->output_name; + *name = convert_uint32_into_string(data).release(); + if (!strlen(*name)) { // empty string. + LOG("(%p) name of %s device is empty!", stm, + type == CUBEB_DEVICE_TYPE_INPUT ? "input" : "output"); + } + return CUBEB_OK; ++ #endif + } + + int + audiounit_stream_get_current_device(cubeb_stream * stm, + cubeb_device ** const device) + { + #if TARGET_OS_IPHONE + // TODO +@@ -3178,16 +3250,17 @@ audiounit_stream_register_device_changed + auto_lock dev_cb_lock(stream->device_changed_callback_lock); + /* Note: second register without unregister first causes 'nope' error. + * Current implementation requires unregister before register a new cb. */ + assert(!device_changed_callback || !stream->device_changed_callback); + stream->device_changed_callback = device_changed_callback; + return CUBEB_OK; + } + ++#if !TARGET_OS_IPHONE + static char * + audiounit_strref_to_cstr_utf8(CFStringRef strref) + { + CFIndex len, size; + char * ret; + if (strref == NULL) { + return NULL; + } +@@ -3199,22 +3272,24 @@ audiounit_strref_to_cstr_utf8(CFStringRe + + if (!CFStringGetCString(strref, ret, size, kCFStringEncodingUTF8)) { + delete[] ret; + ret = NULL; + } + + return ret; + } +- ++#endif ++ ++#if !TARGET_OS_IPHONE + static uint32_t + audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope) + { + AudioObjectPropertyAddress adr = {0, scope, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + UInt32 size = 0; + uint32_t i, ret = 0; + + adr.mSelector = kAudioDevicePropertyStreamConfiguration; + + if (AudioObjectGetPropertyDataSize(devid, &adr, 0, NULL, &size) == noErr && + size > 0) { + AudioBufferList * list = static_cast(alloca(size)); +@@ -3230,17 +3305,17 @@ audiounit_get_channel_count(AudioObjectI + + static void + audiounit_get_available_samplerate(AudioObjectID devid, + AudioObjectPropertyScope scope, + uint32_t * min, uint32_t * max, + uint32_t * def) + { + AudioObjectPropertyAddress adr = {0, scope, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + + adr.mSelector = kAudioDevicePropertyNominalSampleRate; + if (AudioObjectHasProperty(devid, &adr)) { + UInt32 size = sizeof(Float64); + Float64 fvalue = 0.0; + if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &fvalue) == + noErr) { + *def = fvalue; +@@ -3272,17 +3347,17 @@ audiounit_get_available_samplerate(Audio + } + } + + static UInt32 + audiounit_get_device_presentation_latency(AudioObjectID devid, + AudioObjectPropertyScope scope) + { + AudioObjectPropertyAddress adr = {0, scope, +- kAudioObjectPropertyElementMaster}; ++ kAudioObjectPropertyElementMain}; + UInt32 size, dev, stream = 0; + AudioStreamID sid[1]; + + adr.mSelector = kAudioDevicePropertyLatency; + size = sizeof(UInt32); + if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &dev) != noErr) { + dev = 0; + } +@@ -3297,28 +3372,32 @@ audiounit_get_device_presentation_latenc + + return dev + stream; + } + + static int + audiounit_create_device_from_hwdev(cubeb_device_info * dev_info, + AudioObjectID devid, cubeb_device_type type) + { +- AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMaster}; ++ AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMain}; + UInt32 size; + + if (type == CUBEB_DEVICE_TYPE_OUTPUT) { + adr.mScope = kAudioDevicePropertyScopeOutput; + } else if (type == CUBEB_DEVICE_TYPE_INPUT) { + adr.mScope = kAudioDevicePropertyScopeInput; + } else { + return CUBEB_ERROR; + } + ++ #if TARGET_OS_IPHONE ++ UINT32 ch = 2; ++ #else + UInt32 ch = audiounit_get_channel_count(devid, adr.mScope); ++ #endif + if (ch == 0) { + return CUBEB_ERROR; + } + + PodZero(dev_info, 1); + + CFStringRef device_id_str = nullptr; + size = sizeof(CFStringRef); +@@ -3412,17 +3491,26 @@ audiounit_create_device_from_hwdev(cubeb + + bool + is_aggregate_device(cubeb_device_info * device_info) + { + assert(device_info->friendly_name); + return !strncmp(device_info->friendly_name, PRIVATE_AGGREGATE_DEVICE_NAME, + strlen(PRIVATE_AGGREGATE_DEVICE_NAME)); + } +- ++#endif ++ ++#if TARGET_OS_IPHONE ++static int ++audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type, ++ cubeb_device_collection * collection) ++{ ++ return CUBEB_ERROR_NOT_SUPPORTED; ++} ++#else + static int + audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type, + cubeb_device_collection * collection) + { + vector input_devs; + vector output_devs; + + // Count number of input and output devices. This is not +@@ -3478,29 +3566,35 @@ audiounit_enumerate_devices(cubeb * /* c + + static void + audiounit_device_destroy(cubeb_device_info * device) + { + delete[] device->device_id; + delete[] device->friendly_name; + delete[] device->vendor_name; + } ++#endif + + static int + audiounit_device_collection_destroy(cubeb * /* context */, + cubeb_device_collection * collection) + { ++ #if TARGET_OS_IPHONE ++ return CUBEB_ERROR_NOT_SUPPORTED; ++ #else + for (size_t i = 0; i < collection->count; i++) { + audiounit_device_destroy(&collection->device[i]); + } + delete[] collection->device; + + return CUBEB_OK; ++ #endif + } + ++#if !TARGET_OS_IPHONE + static vector + audiounit_get_devices_of_type(cubeb_device_type devtype) + { + UInt32 size = 0; + OSStatus ret = AudioObjectGetPropertyDataSize( + kAudioObjectSystemObject, &DEVICES_PROPERTY_ADDRESS, 0, NULL, &size); + if (ret != noErr) { + return vector(); +@@ -3653,17 +3747,28 @@ audiounit_remove_device_listener(cubeb * + 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); + } +- ++#endif ++ ++#if TARGET_OS_IPHONE ++int ++audiounit_register_device_collection_changed( ++ cubeb * context, cubeb_device_type devtype, ++ cubeb_device_collection_changed_callback collection_changed_callback, ++ void * user_ptr) ++{ ++ return CUBEB_ERROR_NOT_SUPPORTED; ++} ++#else + int + audiounit_register_device_collection_changed( + cubeb * context, cubeb_device_type devtype, + cubeb_device_collection_changed_callback collection_changed_callback, + void * user_ptr) + { + if (devtype == CUBEB_DEVICE_TYPE_UNKNOWN) { + return CUBEB_ERROR_INVALID_PARAMETER; +@@ -3673,16 +3778,17 @@ audiounit_register_device_collection_cha + if (collection_changed_callback) { + ret = audiounit_add_device_listener(context, devtype, + collection_changed_callback, user_ptr); + } else { + ret = audiounit_remove_device_listener(context, devtype); + } + return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR; + } ++#endif + + cubeb_ops const audiounit_ops = { + /*.init =*/audiounit_init, + /*.get_backend_id =*/audiounit_get_backend_id, + /*.get_max_channel_count =*/audiounit_get_max_channel_count, + /*.get_min_latency =*/audiounit_get_min_latency, + /*.get_preferred_sample_rate =*/audiounit_get_preferred_sample_rate, + /*.get_supported_input_processing_params =*/NULL, diff --git a/media/libcubeb/0005-aaudio-timing-fix.patch b/media/libcubeb/0005-aaudio-timing-fix.patch new file mode 100644 index 0000000000..aabaec9c50 --- /dev/null +++ b/media/libcubeb/0005-aaudio-timing-fix.patch @@ -0,0 +1,57 @@ +From 19fcbefe1a9c5e22f8111af251df27b41658bc77 Mon Sep 17 00:00:00 2001 +From: John Lin +Date: Mon, 29 Apr 2024 13:46:57 -0700 +Subject: [PATCH] Invalidate timing info buffers when destorying AAudio stream. + +aaudio_stream_get_position() returns incorrect result because +aaudio_stream_init() recycled destroyed stream where the +timing_info buffers contain stale data. +--- + src/cubeb_aaudio.cpp | 2 ++ + src/cubeb_triple_buffer.h | 7 +++++++ + test/test_triple_buffer.cpp | 3 +++ + 3 files changed, 12 insertions(+) + +diff --git a/src/cubeb_aaudio.cpp b/src/cubeb_aaudio.cpp +index cfae2d6f..8b5eb231 100644 +--- a/src/cubeb_aaudio.cpp ++++ b/src/cubeb_aaudio.cpp +@@ -1049,6 +1049,8 @@ aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard & lock) + stm->istream = nullptr; + } + ++ stm->timing_info.invalidate(); ++ + if (stm->resampler) { + cubeb_resampler_destroy(stm->resampler); + stm->resampler = nullptr; +diff --git a/src/cubeb_triple_buffer.h b/src/cubeb_triple_buffer.h +index a5a5978f..759b92e6 100644 +--- a/src/cubeb_triple_buffer.h ++++ b/src/cubeb_triple_buffer.h +@@ -42,6 +42,13 @@ template class triple_buffer { + { + return (shared_state.load(std::memory_order_relaxed) & BACK_DIRTY_BIT) != 0; + } ++ // Reset state and indices to initial values. ++ void invalidate() ++ { ++ shared_state.store(0, std::memory_order_release); ++ input_idx = 1; ++ output_idx = 2; ++ } + + private: + // Publish a value to the consumer. Returns true if the data was overwritten +diff --git a/test/test_triple_buffer.cpp b/test/test_triple_buffer.cpp +index a6e0049b..d463c07e 100644 +--- a/test/test_triple_buffer.cpp ++++ b/test/test_triple_buffer.cpp +@@ -64,4 +64,7 @@ TEST(cubeb, triple_buffer) + } + + t.join(); ++ ++ buffer.invalidate(); ++ ASSERT_FALSE(buffer.updated()); + } diff --git a/media/libcubeb/moz.yaml b/media/libcubeb/moz.yaml index d79e64b5eb..3444bdb1d6 100644 --- a/media/libcubeb/moz.yaml +++ b/media/libcubeb/moz.yaml @@ -20,6 +20,8 @@ vendoring: - 0001-disable-aaudio-before-android-31.patch - 0002-disable-crash-reporter-death-test.patch - 0003-Only-build-duplex_collection_change_no_unregister-wh.patch + - 0004-audiounit-ios-compile-fixes.patch + - 0005-aaudio-timing-fix.patch skip-vendoring-steps: - update-moz-build exclude: diff --git a/media/libcubeb/src/cubeb_aaudio.cpp b/media/libcubeb/src/cubeb_aaudio.cpp index df19602cd6..c2441bbeef 100644 --- a/media/libcubeb/src/cubeb_aaudio.cpp +++ b/media/libcubeb/src/cubeb_aaudio.cpp @@ -1039,6 +1039,8 @@ aaudio_stream_destroy_locked(cubeb_stream * stm, lock_guard & lock) stm->istream = nullptr; } + stm->timing_info.invalidate(); + if (stm->resampler) { cubeb_resampler_destroy(stm->resampler); stm->resampler = nullptr; diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp index d823e80ff8..fb15790159 100644 --- a/media/libcubeb/src/cubeb_audiounit.cpp +++ b/media/libcubeb/src/cubeb_audiounit.cpp @@ -41,6 +41,15 @@ using namespace std; typedef UInt32 AudioFormatFlags; #endif +#if TARGET_OS_IPHONE +typedef UInt32 AudioDeviceID; +typedef UInt32 AudioObjectID; +const UInt32 kAudioObjectUnknown = 0; + +#define AudioGetCurrentHostTime mach_absolute_time + +#endif + #define AU_OUT_BUS 0 #define AU_IN_BUS 1 @@ -65,6 +74,7 @@ const char * PRIVATE_AGGREGATE_DEVICE_NAME = "CubebAggregateDevice"; LOG(msg, ##__VA_ARGS__); \ }) +#if !TARGET_OS_IPHONE /* Testing empirically, some headsets report a minimal latency that is very * low, but this does not work in practice. Lie and say the minimum is 256 * frames. */ @@ -73,27 +83,28 @@ const uint32_t SAFE_MAX_LATENCY_FRAMES = 512; const AudioObjectPropertyAddress DEFAULT_INPUT_DEVICE_PROPERTY_ADDRESS = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; const AudioObjectPropertyAddress DEFAULT_OUTPUT_DEVICE_PROPERTY_ADDRESS = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; const AudioObjectPropertyAddress DEVICE_IS_ALIVE_PROPERTY_ADDRESS = { kAudioDevicePropertyDeviceIsAlive, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; const AudioObjectPropertyAddress DEVICES_PROPERTY_ADDRESS = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; const AudioObjectPropertyAddress INPUT_DATA_SOURCE_PROPERTY_ADDRESS = { kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeInput, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; const AudioObjectPropertyAddress OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS = { kAudioDevicePropertyDataSource, kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; +#endif typedef uint32_t device_flags_value; @@ -114,22 +125,22 @@ static void audiounit_close_stream(cubeb_stream * stm); static int audiounit_setup_stream(cubeb_stream * stm); +#if !TARGET_OS_IPHONE static vector audiounit_get_devices_of_type(cubeb_device_type devtype); static UInt32 audiounit_get_device_presentation_latency(AudioObjectID devid, AudioObjectPropertyScope scope); - -#if !TARGET_OS_IPHONE static AudioObjectID audiounit_get_default_device_id(cubeb_device_type type); static int audiounit_uninstall_device_changed_callback(cubeb_stream * stm); static int audiounit_uninstall_system_changed_callback(cubeb_stream * stm); +#endif + static void audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags); -#endif extern cubeb_ops const audiounit_ops; @@ -144,9 +155,11 @@ struct cubeb { cubeb_device_collection_changed_callback output_collection_changed_callback = nullptr; void * output_collection_changed_user_ptr = nullptr; + #if !TARGET_OS_IPHONE // Store list of devices to detect changes vector input_device_array; vector output_device_array; + #endif // The queue should be released when it’s no longer needed. dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL); @@ -186,6 +199,7 @@ struct device_info { device_flags_value flags = DEV_UNKNOWN; }; +#if !TARGET_OS_IPHONE struct property_listener { AudioDeviceID device_id; const AudioObjectPropertyAddress * property_address; @@ -199,6 +213,7 @@ struct property_listener { { } }; +#endif struct cubeb_stream { explicit cubeb_stream(cubeb * context); @@ -257,22 +272,26 @@ struct cubeb_stream { /* This is true if a device change callback is currently running. */ atomic switching_device{false}; atomic buffer_size_change_state{false}; + #if !TARGET_OS_IPHONE AudioDeviceID aggregate_device_id = kAudioObjectUnknown; // the aggregate device id AudioObjectID plugin_id = kAudioObjectUnknown; // used to create aggregate device + #endif /* Mixer interface */ unique_ptr mixer; /* Buffer where remixing/resampling will occur when upmixing is required */ /* Only accessed from callback thread */ unique_ptr temp_buffer; size_t temp_buffer_size = 0; // size in bytes. + #if !TARGET_OS_IPHONE /* Listeners indicating what system events are monitored. */ unique_ptr default_input_listener; unique_ptr default_output_listener; unique_ptr input_alive_listener; unique_ptr input_source_listener; unique_ptr output_source_listener; + #endif }; bool @@ -386,14 +405,6 @@ is_common_sample_rate(Float64 sample_rate) sample_rate == 88200 || sample_rate == 96000; } -#if TARGET_OS_IPHONE -typedef UInt32 AudioDeviceID; -typedef UInt32 AudioObjectID; - -#define AudioGetCurrentHostTime mach_absolute_time - -#endif - uint64_t ConvertHostTimeToNanos(uint64_t host_time) { @@ -761,13 +772,13 @@ audiounit_get_backend_id(cubeb * /* ctx */) return "audiounit"; } -#if !TARGET_OS_IPHONE static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume); static int audiounit_stream_set_volume(cubeb_stream * stm, float volume); +#if !TARGET_OS_IPHONE static int audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side) { @@ -811,6 +822,7 @@ audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side) return CUBEB_OK; } +#endif static int audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) @@ -822,10 +834,13 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) audiounit_stream_stop_internal(stm); } - int r = audiounit_uninstall_device_changed_callback(stm); + int r; +#if !TARGET_OS_IPHONE + r = audiounit_uninstall_device_changed_callback(stm); if (r != CUBEB_OK) { LOG("(%p) Could not uninstall all device change listeners.", stm); } +#endif { auto_lock lock(stm->mutex); @@ -837,6 +852,7 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) audiounit_close_stream(stm); + #if !TARGET_OS_IPHONE /* Reinit occurs in one of the following case: * - When the device is not alive any more * - When the default system device change. @@ -866,8 +882,11 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) return CUBEB_ERROR; } + #endif + if (audiounit_setup_stream(stm) != CUBEB_OK) { LOG("(%p) Stream reinit failed.", stm); + #if !TARGET_OS_IPHONE if (flags & DEV_INPUT && input_device != kAudioObjectUnknown) { // Attempt to re-use the same device-id failed, so attempt again with // default input device. @@ -879,6 +898,7 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) return CUBEB_ERROR; } } + #endif } if (vol_rv == CUBEB_OK) { @@ -914,9 +934,11 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags) } if (audiounit_reinit_stream(stm, flags) != CUBEB_OK) { + #if !TARGET_OS_IPHONE if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) { LOG("(%p) Could not uninstall system changed callback", stm); } + #endif stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); LOG("(%p) Could not reopen the stream after switching.", stm); } @@ -925,6 +947,7 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags) }); } +#if !TARGET_OS_IPHONE static char const * event_addr_to_string(AudioObjectPropertySelector selector) { @@ -1096,6 +1119,7 @@ audiounit_install_device_changed_callback(cubeb_stream * stm) return r; } +#if !TARGET_OS_IPHONE static int audiounit_install_system_changed_callback(cubeb_stream * stm) { @@ -1136,6 +1160,7 @@ audiounit_install_system_changed_callback(cubeb_stream * stm) return CUBEB_OK; } +#endif static int audiounit_uninstall_device_changed_callback(cubeb_stream * stm) @@ -1212,7 +1237,7 @@ audiounit_get_acceptable_latency_range(AudioValueRange * latency_range) AudioDeviceID output_device_id; AudioObjectPropertyAddress output_device_buffer_size_range = { kAudioDevicePropertyBufferFrameSizeRange, kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); if (output_device_id == kAudioObjectUnknown) { @@ -1233,7 +1258,6 @@ audiounit_get_acceptable_latency_range(AudioValueRange * latency_range) return CUBEB_OK; } -#endif /* !TARGET_OS_IPHONE */ static AudioObjectID audiounit_get_default_device_id(cubeb_device_type type) @@ -1256,6 +1280,7 @@ audiounit_get_default_device_id(cubeb_device_type type) return devid; } +#endif /* !TARGET_OS_IPHONE */ int audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) @@ -1270,7 +1295,7 @@ audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) AudioStreamBasicDescription stream_format; AudioObjectPropertyAddress stream_format_address = { kAudioDevicePropertyStreamFormat, kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; assert(ctx && max_channels); @@ -1309,17 +1334,16 @@ audiounit_get_min_latency(cubeb * /* ctx */, cubeb_stream_params /* params */, *latency_frames = max(latency_range.mMinimum, SAFE_MIN_LATENCY_FRAMES); -#endif - return CUBEB_OK; +#endif } static int audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate) { #if TARGET_OS_IPHONE - // TODO - return CUBEB_ERROR_NOT_SUPPORTED; + *rate = 44100; + return CUBEB_OK; #else UInt32 size; OSStatus r; @@ -1327,7 +1351,7 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate) AudioDeviceID output_device_id; AudioObjectPropertyAddress samplerate_address = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT); if (output_device_id == kAudioObjectUnknown) { @@ -1343,8 +1367,9 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate) } *rate = static_cast(fsamplerate); -#endif + return CUBEB_OK; +#endif } static cubeb_channel_layout @@ -1385,6 +1410,9 @@ audiounit_convert_channel_layout(AudioChannelLayout * layout) static cubeb_channel_layout audiounit_get_preferred_channel_layout(AudioUnit output_unit) { + #if TARGET_OS_IPHONE + return CUBEB_LAYOUT_STEREO; + #else OSStatus rv = noErr; UInt32 size = 0; rv = AudioUnitGetPropertyInfo( @@ -1409,6 +1437,7 @@ audiounit_get_preferred_channel_layout(AudioUnit output_unit) } return audiounit_convert_channel_layout(layout.get()); + #endif } static cubeb_channel_layout @@ -1442,8 +1471,10 @@ audiounit_get_current_channel_layout(AudioUnit output_unit) static int audiounit_create_unit(AudioUnit * unit, device_info * device); +#if !TARGET_OS_IPHONE static OSStatus audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype); +#endif static void audiounit_destroy(cubeb * ctx) @@ -1465,6 +1496,7 @@ audiounit_destroy(cubeb * ctx) !ctx->output_collection_changed_callback && !ctx->output_collection_changed_user_ptr); + #if !TARGET_OS_IPHONE /* Unregister the callback if necessary. */ if (ctx->input_collection_changed_callback) { audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_INPUT); @@ -1472,6 +1504,7 @@ audiounit_destroy(cubeb * ctx) if (ctx->output_collection_changed_callback) { audiounit_remove_device_listener(ctx, CUBEB_DEVICE_TYPE_OUTPUT); } + #endif } dispatch_release(ctx->serial_queue); @@ -1599,13 +1632,14 @@ audiounit_layout_init(cubeb_stream * stm, io_side side) stm->context->layout); } +#if !TARGET_OS_IPHONE static vector audiounit_get_sub_devices(AudioDeviceID device_id) { vector sub_devices; AudioObjectPropertyAddress property_address = { kAudioAggregateDevicePropertyActiveSubDeviceList, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; UInt32 size = 0; OSStatus rv = AudioObjectGetPropertyDataSize(device_id, &property_address, 0, nullptr, &size); @@ -1634,7 +1668,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, { AudioObjectPropertyAddress address_plugin_bundle_id = { kAudioHardwarePropertyPlugInForBundleID, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; UInt32 size = 0; OSStatus r = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &address_plugin_bundle_id, 0, NULL, &size); @@ -1664,7 +1698,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioObjectPropertyAddress create_aggregate_device_address = { kAudioPlugInCreateAggregateDevice, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; r = AudioObjectGetPropertyDataSize( *plugin_id, &create_aggregate_device_address, 0, nullptr, &size); if (r != noErr) { @@ -1736,7 +1770,7 @@ get_device_name(AudioDeviceID id) CFStringRef UIname = nullptr; AudioObjectPropertyAddress address_uuid = {kAudioDevicePropertyDeviceUID, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; OSStatus err = AudioObjectGetPropertyData(id, &address_uuid, 0, nullptr, &size, &UIname); return (err == noErr) ? UIname : NULL; @@ -1779,7 +1813,7 @@ audiounit_set_aggregate_sub_device_list(AudioDeviceID aggregate_device_id, AudioObjectPropertyAddress aggregate_sub_device_list = { kAudioAggregateDevicePropertyFullSubDeviceList, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; UInt32 size = sizeof(CFMutableArrayRef); OSStatus rv = AudioObjectSetPropertyData( aggregate_device_id, &aggregate_sub_device_list, 0, nullptr, size, @@ -1801,7 +1835,7 @@ audiounit_set_master_aggregate_device(const AudioDeviceID aggregate_device_id) assert(aggregate_device_id != kAudioObjectUnknown); AudioObjectPropertyAddress master_aggregate_sub_device = { kAudioAggregateDevicePropertyMasterSubDevice, - kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMain}; // Master become the 1st output sub device AudioDeviceID output_device_id = @@ -1834,7 +1868,7 @@ audiounit_activate_clock_drift_compensation( assert(aggregate_device_id != kAudioObjectUnknown); AudioObjectPropertyAddress address_owned = { kAudioObjectPropertyOwnedObjects, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; UInt32 qualifier_data_size = sizeof(AudioObjectID); AudioClassID class_id = kAudioSubDeviceClassID; @@ -1866,7 +1900,7 @@ audiounit_activate_clock_drift_compensation( AudioObjectPropertyAddress address_drift = { kAudioSubDevicePropertyDriftCompensation, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; // Start from the second device since the first is the master clock for (UInt32 i = 1; i < subdevices_num; ++i) { @@ -1935,7 +1969,7 @@ audiounit_workaround_for_airpod(cubeb_stream * stm) Float64 rate = input_nominal_rate; AudioObjectPropertyAddress addr = {kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; OSStatus rv = AudioObjectSetPropertyData(stm->aggregate_device_id, &addr, 0, nullptr, sizeof(Float64), &rate); @@ -2019,7 +2053,7 @@ audiounit_destroy_aggregate_device(AudioObjectID plugin_id, plugin_id != kAudioObjectUnknown); AudioObjectPropertyAddress destroy_aggregate_device_addr = { kAudioPlugInDestroyAggregateDevice, kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; UInt32 size; OSStatus rv = AudioObjectGetPropertyDataSize( plugin_id, &destroy_aggregate_device_addr, 0, NULL, &size); @@ -2042,6 +2076,7 @@ audiounit_destroy_aggregate_device(AudioObjectID plugin_id, *aggregate_device_id = kAudioObjectUnknown; return CUBEB_OK; } +#endif static int audiounit_new_unit_instance(AudioUnit * unit, device_info * device) @@ -2178,6 +2213,9 @@ audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity) static uint32_t audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames) { + #if TARGET_OS_IPHONE + return latency_frames; + #else // For the 1st stream set anything within safe min-max assert(audiounit_active_streams(stm->context) > 0); if (audiounit_active_streams(stm->context) == 1) { @@ -2238,8 +2276,10 @@ audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames) return max(min(latency_frames, upper_latency_limit), SAFE_MIN_LATENCY_FRAMES); + #endif } +#if !TARGET_OS_IPHONE /* * Change buffer size is prone to deadlock thus we change it * following the steps: @@ -2290,11 +2330,15 @@ buffer_size_changed_callback(void * inClientData, AudioUnit inUnit, } } } +#endif static int audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side side) { + #if TARGET_OS_IPHONE + return CUBEB_OK; + #else AudioUnit au = stm->output_unit; AudioUnitScope au_scope = kAudioUnitScope_Input; AudioUnitElement au_element = AU_OUT_BUS; @@ -2382,6 +2426,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side), new_size_frames); return CUBEB_OK; + #endif } static int @@ -2598,6 +2643,7 @@ audiounit_setup_stream(cubeb_stream * stm) device_info in_dev_info = stm->input_device; device_info out_dev_info = stm->output_device; + #if !TARGET_OS_IPHONE if (has_input(stm) && has_output(stm) && stm->input_device.id != stm->output_device.id) { r = audiounit_create_aggregate_device(stm); @@ -2615,6 +2661,10 @@ audiounit_setup_stream(cubeb_stream * stm) out_dev_info.flags = DEV_OUTPUT; } } + #else + in_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_INPUT; + out_dev_info.flags = DEV_SYSTEM_DEFAULT | DEV_OUTPUT; + #endif if (has_input(stm)) { r = audiounit_create_unit(&stm->input_unit, &in_dev_info); @@ -2756,8 +2806,10 @@ audiounit_setup_stream(cubeb_stream * stm) return CUBEB_ERROR; } + #if !TARGET_OS_IPHONE stm->current_latency_frames = audiounit_get_device_presentation_latency( stm->output_device.id, kAudioDevicePropertyScopeOutput); + #endif Float64 unit_s; UInt32 size = sizeof(unit_s); @@ -2777,10 +2829,12 @@ audiounit_setup_stream(cubeb_stream * stm) ceilf(stm->output_hw_rate / stm->input_hw_rate); } + #if !TARGET_OS_IPHONE r = audiounit_install_device_changed_callback(stm); if (r != CUBEB_OK) { LOG("(%p) Could not install all device change callback.", stm); } + #endif return CUBEB_OK; } @@ -2828,21 +2882,25 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, } if (input_stream_params) { stm->input_stream_params = *input_stream_params; + #if !TARGET_OS_IPHONE r = audiounit_set_device_info( stm.get(), reinterpret_cast(input_device), io_side::INPUT); if (r != CUBEB_OK) { LOG("(%p) Fail to set device info for input.", stm.get()); return r; } + #endif } if (output_stream_params) { stm->output_stream_params = *output_stream_params; + #if !TARGET_OS_IPHONE r = audiounit_set_device_info( stm.get(), reinterpret_cast(output_device), io_side::OUTPUT); if (r != CUBEB_OK) { LOG("(%p) Fail to set device info for output.", stm.get()); return r; } + #endif } { @@ -2858,11 +2916,13 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, return r; } + #if !TARGET_OS_IPHONE r = audiounit_install_system_changed_callback(stm.get()); if (r != CUBEB_OK) { LOG("(%p) Could not install the device change callback.", stm.get()); return r; } + #endif *stream = stm.release(); LOG("(%p) Cubeb stream init successful.", *stream); @@ -2891,11 +2951,13 @@ audiounit_close_stream(cubeb_stream * stm) stm->resampler.reset(); stm->mixer.reset(); + #if !TARGET_OS_IPHONE if (stm->aggregate_device_id != kAudioObjectUnknown) { audiounit_destroy_aggregate_device(stm->plugin_id, &stm->aggregate_device_id); stm->aggregate_device_id = kAudioObjectUnknown; } + #endif } static void @@ -2903,6 +2965,7 @@ audiounit_stream_destroy_internal(cubeb_stream * stm) { stm->context->mutex.assert_current_thread_owns(); +#if !TARGET_OS_IPHONE int r = audiounit_uninstall_system_changed_callback(stm); if (r != CUBEB_OK) { LOG("(%p) Could not uninstall the device changed callback", stm); @@ -2911,6 +2974,7 @@ audiounit_stream_destroy_internal(cubeb_stream * stm) if (r != CUBEB_OK) { LOG("(%p) Could not uninstall all device change listeners", stm); } +#endif auto_lock lock(stm->mutex); audiounit_close_stream(stm); @@ -2921,6 +2985,7 @@ audiounit_stream_destroy_internal(cubeb_stream * stm) static void audiounit_stream_destroy(cubeb_stream * stm) { + #if !TARGET_OS_IPHONE int r = audiounit_uninstall_system_changed_callback(stm); if (r != CUBEB_OK) { LOG("(%p) Could not uninstall the device changed callback", stm); @@ -2929,6 +2994,7 @@ audiounit_stream_destroy(cubeb_stream * stm) if (r != CUBEB_OK) { LOG("(%p) Could not uninstall all device change listeners", stm); } + #endif if (!stm->shutdown.load()) { auto_lock context_lock(stm->context->mutex); @@ -3086,6 +3152,7 @@ convert_uint32_into_string(UInt32 data) return str; } +#if !TARGET_OS_IPHONE int audiounit_get_default_device_datasource(cubeb_device_type type, UInt32 * data) { @@ -3107,12 +3174,16 @@ audiounit_get_default_device_datasource(cubeb_device_type type, UInt32 * data) return CUBEB_OK; } +#endif int audiounit_get_default_device_name(cubeb_stream * stm, cubeb_device * const device, cubeb_device_type type) { +#if TARGET_OS_IPHONE + return CUBEB_ERROR_NOT_SUPPORTED; +#else assert(stm); assert(device); @@ -3129,6 +3200,7 @@ audiounit_get_default_device_name(cubeb_stream * stm, type == CUBEB_DEVICE_TYPE_INPUT ? "input" : "output"); } return CUBEB_OK; + #endif } int @@ -3183,6 +3255,7 @@ audiounit_stream_register_device_changed_callback( return CUBEB_OK; } +#if !TARGET_OS_IPHONE static char * audiounit_strref_to_cstr_utf8(CFStringRef strref) { @@ -3204,12 +3277,14 @@ audiounit_strref_to_cstr_utf8(CFStringRef strref) return ret; } +#endif +#if !TARGET_OS_IPHONE static uint32_t audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope) { AudioObjectPropertyAddress adr = {0, scope, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; UInt32 size = 0; uint32_t i, ret = 0; @@ -3235,7 +3310,7 @@ audiounit_get_available_samplerate(AudioObjectID devid, uint32_t * def) { AudioObjectPropertyAddress adr = {0, scope, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; adr.mSelector = kAudioDevicePropertyNominalSampleRate; if (AudioObjectHasProperty(devid, &adr)) { @@ -3277,7 +3352,7 @@ audiounit_get_device_presentation_latency(AudioObjectID devid, AudioObjectPropertyScope scope) { AudioObjectPropertyAddress adr = {0, scope, - kAudioObjectPropertyElementMaster}; + kAudioObjectPropertyElementMain}; UInt32 size, dev, stream = 0; AudioStreamID sid[1]; @@ -3302,7 +3377,7 @@ static int audiounit_create_device_from_hwdev(cubeb_device_info * dev_info, AudioObjectID devid, cubeb_device_type type) { - AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMaster}; + AudioObjectPropertyAddress adr = {0, 0, kAudioObjectPropertyElementMain}; UInt32 size; if (type == CUBEB_DEVICE_TYPE_OUTPUT) { @@ -3313,7 +3388,11 @@ audiounit_create_device_from_hwdev(cubeb_device_info * dev_info, return CUBEB_ERROR; } + #if TARGET_OS_IPHONE + UINT32 ch = 2; + #else UInt32 ch = audiounit_get_channel_count(devid, adr.mScope); + #endif if (ch == 0) { return CUBEB_ERROR; } @@ -3417,7 +3496,16 @@ is_aggregate_device(cubeb_device_info * device_info) return !strncmp(device_info->friendly_name, PRIVATE_AGGREGATE_DEVICE_NAME, strlen(PRIVATE_AGGREGATE_DEVICE_NAME)); } +#endif +#if TARGET_OS_IPHONE +static int +audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type, + cubeb_device_collection * collection) +{ + return CUBEB_ERROR_NOT_SUPPORTED; +} +#else static int audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type, cubeb_device_collection * collection) @@ -3483,19 +3571,25 @@ audiounit_device_destroy(cubeb_device_info * device) delete[] device->friendly_name; delete[] device->vendor_name; } +#endif static int audiounit_device_collection_destroy(cubeb * /* context */, cubeb_device_collection * collection) { + #if TARGET_OS_IPHONE + return CUBEB_ERROR_NOT_SUPPORTED; + #else for (size_t i = 0; i < collection->count; i++) { audiounit_device_destroy(&collection->device[i]); } delete[] collection->device; return CUBEB_OK; + #endif } +#if !TARGET_OS_IPHONE static vector audiounit_get_devices_of_type(cubeb_device_type devtype) { @@ -3658,7 +3752,18 @@ audiounit_remove_device_listener(cubeb * context, cubeb_device_type devtype) kAudioObjectSystemObject, &DEVICES_PROPERTY_ADDRESS, audiounit_collection_changed_callback, context); } +#endif +#if TARGET_OS_IPHONE +int +audiounit_register_device_collection_changed( + cubeb * context, cubeb_device_type devtype, + cubeb_device_collection_changed_callback collection_changed_callback, + void * user_ptr) +{ + return CUBEB_ERROR_NOT_SUPPORTED; +} +#else int audiounit_register_device_collection_changed( cubeb * context, cubeb_device_type devtype, @@ -3678,6 +3783,7 @@ audiounit_register_device_collection_changed( } return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR; } +#endif cubeb_ops const audiounit_ops = { /*.init =*/audiounit_init, diff --git a/media/libcubeb/src/cubeb_triple_buffer.h b/media/libcubeb/src/cubeb_triple_buffer.h index a5a5978fb4..759b92e62b 100644 --- a/media/libcubeb/src/cubeb_triple_buffer.h +++ b/media/libcubeb/src/cubeb_triple_buffer.h @@ -42,6 +42,13 @@ public: { return (shared_state.load(std::memory_order_relaxed) & BACK_DIRTY_BIT) != 0; } + // Reset state and indices to initial values. + void invalidate() + { + shared_state.store(0, std::memory_order_release); + input_idx = 1; + output_idx = 2; + } private: // Publish a value to the consumer. Returns true if the data was overwritten diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build index d7d05b5867..46a89c4063 100644 --- a/media/libcubeb/src/moz.build +++ b/media/libcubeb/src/moz.build @@ -74,8 +74,8 @@ if CONFIG['MOZ_AUDIOUNIT_RUST']: SOURCES += [ 'cubeb_osx_run_loop.c', ] + DEFINES['USE_AUDIOUNIT_RUST'] = True DEFINES['USE_AUDIOUNIT'] = True - DEFINES['USE_AUDIOUNIT_RUST'] = True if CONFIG['MOZ_WASAPI']: SOURCES += [ diff --git a/media/libcubeb/test/test_triple_buffer.cpp b/media/libcubeb/test/test_triple_buffer.cpp index a6e0049b79..d463c07e03 100644 --- a/media/libcubeb/test/test_triple_buffer.cpp +++ b/media/libcubeb/test/test_triple_buffer.cpp @@ -64,4 +64,7 @@ TEST(cubeb, triple_buffer) } t.join(); + + buffer.invalidate(); + ASSERT_FALSE(buffer.updated()); } -- cgit v1.2.3