summaryrefslogtreecommitdiffstats
path: root/media/libcubeb
diff options
context:
space:
mode:
Diffstat (limited to 'media/libcubeb')
-rw-r--r--media/libcubeb/0004-audiounit-ios-compile-fixes.patch1415
-rw-r--r--media/libcubeb/0005-aaudio-timing-fix.patch57
-rw-r--r--media/libcubeb/moz.yaml2
-rw-r--r--media/libcubeb/src/cubeb_aaudio.cpp2
-rw-r--r--media/libcubeb/src/cubeb_audiounit.cpp190
-rw-r--r--media/libcubeb/src/cubeb_triple_buffer.h7
-rw-r--r--media/libcubeb/src/moz.build2
-rw-r--r--media/libcubeb/test/test_triple_buffer.cpp3
8 files changed, 1635 insertions, 43 deletions
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 <vector>
+
+ 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<AudioObjectID>
+ 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<AudioObjectID> input_device_array;
+ vector<AudioObjectID> 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<cubeb_channel_layout> 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<uint32_t> current_latency_frames{0};
+ atomic<uint32_t> total_output_latency_frames{0};
+ unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler;
+ /* This is true if a device change callback is currently running. */
+ atomic<bool> switching_device{false};
+ atomic<bool> 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<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer;
+ /* Buffer where remixing/resampling will occur when upmixing is required */
+ /* Only accessed from callback thread */
+ unique_ptr<uint8_t[]> temp_buffer;
+ size_t temp_buffer_size = 0; // size in bytes.
++ #if !TARGET_OS_IPHONE
+ /* Listeners indicating what system events are monitored. */
+ unique_ptr<property_listener> default_input_listener;
+ unique_ptr<property_listener> default_output_listener;
+ unique_ptr<property_listener> input_alive_listener;
+ unique_ptr<property_listener> input_source_listener;
+ unique_ptr<property_listener> 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<uint32_t>(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<uint32_t>(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<AudioObjectID>
+ audiounit_get_sub_devices(AudioDeviceID device_id)
+ {
+ vector<AudioDeviceID> 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<AudioDeviceID> 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<uint32_t>(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<uint32_t>(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<uint32_t>(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<uintptr_t>(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<uintptr_t>(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<AudioBufferList *>(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<AudioObjectID> input_devs;
+ vector<AudioObjectID> 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<AudioObjectID>
+ 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<AudioObjectID>();
+@@ -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 <jolin@mozilla.com>
+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<mutex> & 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 <typename T> 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<mutex> & 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<AudioObjectID>
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<AudioObjectID> input_device_array;
vector<AudioObjectID> 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<bool> switching_device{false};
atomic<bool> 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<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer;
/* Buffer where remixing/resampling will occur when upmixing is required */
/* Only accessed from callback thread */
unique_ptr<uint8_t[]> temp_buffer;
size_t temp_buffer_size = 0; // size in bytes.
+ #if !TARGET_OS_IPHONE
/* Listeners indicating what system events are monitored. */
unique_ptr<property_listener> default_input_listener;
unique_ptr<property_listener> default_output_listener;
unique_ptr<property_listener> input_alive_listener;
unique_ptr<property_listener> input_source_listener;
unique_ptr<property_listener> 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<uint32_t>(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<uint32_t>(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<AudioObjectID>
audiounit_get_sub_devices(AudioDeviceID device_id)
{
vector<AudioDeviceID> 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<uint32_t>(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<uintptr_t>(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<uintptr_t>(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<AudioObjectID>
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());
}