diff options
Diffstat (limited to 'media/libcubeb/osx-linearize-operations.patch')
-rw-r--r-- | media/libcubeb/osx-linearize-operations.patch | 968 |
1 files changed, 0 insertions, 968 deletions
diff --git a/media/libcubeb/osx-linearize-operations.patch b/media/libcubeb/osx-linearize-operations.patch deleted file mode 100644 index 9f4f31bca..000000000 --- a/media/libcubeb/osx-linearize-operations.patch +++ /dev/null @@ -1,968 +0,0 @@ -From: Paul Adenot <paul@paul.cx> -Subject: Linearize operations on AudioUnits to sidestep a deadlock. - ---- - -diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp ---- a/src/cubeb_audiounit.cpp -+++ b/src/cubeb_audiounit.cpp -@@ -53,40 +53,45 @@ typedef UInt32 AudioFormatFlags; - - #define AU_OUT_BUS 0 - #define AU_IN_BUS 1 - - #define PRINT_ERROR_CODE(str, r) do { \ - LOG("System call failed: %s (rv: %d)", str, r); \ - } while(0) - -+const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb"; -+ - /* 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 = 256; - const uint32_t SAFE_MAX_LATENCY_FRAMES = 512; - - void audiounit_stream_stop_internal(cubeb_stream * stm); - void audiounit_stream_start_internal(cubeb_stream * stm); --static void close_audiounit_stream(cubeb_stream * stm); --static int setup_audiounit_stream(cubeb_stream * stm); -+static void audiounit_close_stream(cubeb_stream *stm); -+static int audiounit_setup_stream(cubeb_stream *stm); - - extern cubeb_ops const audiounit_ops; - - struct cubeb { - cubeb_ops const * ops; - owned_critical_section mutex; - std::atomic<int> active_streams; -+ uint32_t global_latency_frames = 0; - int limit_streams; - cubeb_device_collection_changed_callback collection_changed_callback; - void * collection_changed_user_ptr; - /* Differentiate input from output devices. */ - cubeb_device_type collection_changed_devtype; - uint32_t devtype_device_count; - AudioObjectID * devtype_device_array; -+ // The queue is asynchronously deallocated once all references to it are released -+ dispatch_queue_t serial_queue = dispatch_queue_create(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL); - }; - - class auto_array_wrapper - { - public: - explicit auto_array_wrapper(auto_array<float> * ar) - : float_ar(ar) - , short_ar(nullptr) -@@ -205,16 +210,17 @@ struct cubeb_stream { - cubeb_resampler * resampler; - /* This is the number of output callback we got in a row. This is usually one, - * but can be two when the input and output rate are different, and more when - * a device has been plugged or unplugged, as there can be some time before - * the device is ready. */ - std::atomic<int> output_callback_in_a_row; - /* This is true if a device change callback is currently running. */ - std::atomic<bool> switching_device; -+ std::atomic<bool> buffer_size_change_state{ false }; - }; - - bool has_input(cubeb_stream * stm) - { - return stm->input_stream_params.rate != 0; - } - - bool has_output(cubeb_stream * stm) -@@ -256,16 +262,24 @@ audiotimestamp_to_latency(AudioTimeStamp - - uint64_t pres = AudioConvertHostTimeToNanos(tstamp->mHostTime); - uint64_t now = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime()); - - return ((pres - now) * stream->output_desc.mSampleRate) / 1000000000LL; - } - - static void -+audiounit_set_global_latency(cubeb_stream * stm, uint32_t latency_frames) -+{ -+ stm->mutex.assert_current_thread_owns(); -+ assert(stm->context->active_streams == 1); -+ stm->context->global_latency_frames = latency_frames; -+} -+ -+static void - audiounit_make_silent(AudioBuffer * ioData) - { - assert(ioData); - assert(ioData->mData); - memset(ioData->mData, 0, ioData->mDataByteSize); - } - - static OSStatus -@@ -576,29 +590,54 @@ audiounit_get_input_device_id(AudioDevic - device_id); - if (r != noErr) { - return CUBEB_ERROR; - } - - return CUBEB_OK; - } - -+static int -+audiounit_reinit_stream(cubeb_stream * stm, bool is_started) -+{ -+ if (is_started) { -+ audiounit_stream_stop_internal(stm); -+ } -+ -+ { -+ auto_lock lock(stm->mutex); -+ -+ audiounit_close_stream(stm); -+ -+ if (audiounit_setup_stream(stm) != CUBEB_OK) { -+ LOG("(%p) Stream reinit failed.", stm); -+ return CUBEB_ERROR; -+ } -+ -+ // Reset input frames to force new stream pre-buffer -+ // silence if needed, check `is_extra_input_needed()` -+ stm->frames_read = 0; -+ -+ // If the stream was running, start it again. -+ if (is_started) { -+ audiounit_stream_start_internal(stm); -+ } -+ } -+ return CUBEB_OK; -+} -+ - static OSStatus - audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count, - const AudioObjectPropertyAddress * addresses, - void * user) - { - cubeb_stream * stm = (cubeb_stream*) user; -- int rv; -- bool was_running = false; -- - stm->switching_device = true; -- - // Note if the stream was running or not -- was_running = !stm->shutdown; -+ bool was_running = !stm->shutdown; - - LOG("(%p) Audio device changed, %d events.", stm, address_count); - for (UInt32 i = 0; i < address_count; i++) { - switch(addresses[i].mSelector) { - case kAudioHardwarePropertyDefaultOutputDevice: { - LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i); - // Allow restart to choose the new default - stm->output_device = nullptr; -@@ -639,38 +678,25 @@ audiounit_property_listener_callback(Aud - if (stm->device_changed_callback) { - stm->device_changed_callback(stm->user_ptr); - } - break; - } - } - } - -- // This means the callback won't be called again. -- audiounit_stream_stop_internal(stm); -- -- { -- auto_lock lock(stm->mutex); -- close_audiounit_stream(stm); -- rv = setup_audiounit_stream(stm); -- if (rv != CUBEB_OK) { -- LOG("(%p) Could not reopen a stream after switching.", stm); -+ // Use a new thread, through the queue, to avoid deadlock when calling -+ // Get/SetProperties method from inside notify callback -+ dispatch_async(stm->context->serial_queue, ^() { -+ if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) { - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); -- return noErr; -+ LOG("(%p) Could not reopen the stream after switching.", stm); - } -- -- stm->frames_read = 0; -- -- // If the stream was running, start it again. -- if (was_running) { -- audiounit_stream_start_internal(stm); -- } -- } -- -- stm->switching_device = false; -+ stm->switching_device = false; -+ }); - - return noErr; - } - - OSStatus - audiounit_add_listener(cubeb_stream * stm, AudioDeviceID id, AudioObjectPropertySelector selector, - AudioObjectPropertyScope scope, AudioObjectPropertyListenerProc listener) - { -@@ -1155,18 +1181,17 @@ audiounit_init_input_linear_buffer(cubeb - - static void - audiounit_destroy_input_linear_buffer(cubeb_stream * stream) - { - delete stream->input_linear_buffer; - } - - static uint32_t --audiounit_clamp_latency(cubeb_stream * stm, -- uint32_t latency_frames) -+audiounit_clamp_latency(cubeb_stream * stm, uint32_t latency_frames) - { - // For the 1st stream set anything within safe min-max - assert(stm->context->active_streams > 0); - if (stm->context->active_streams == 1) { - return std::max(std::min<uint32_t>(latency_frames, SAFE_MAX_LATENCY_FRAMES), - SAFE_MIN_LATENCY_FRAMES); - } - -@@ -1219,26 +1244,374 @@ audiounit_clamp_latency(cubeb_stream * s - } else { - upper_latency_limit = SAFE_MAX_LATENCY_FRAMES; - } - - return std::max(std::min<uint32_t>(latency_frames, upper_latency_limit), - SAFE_MIN_LATENCY_FRAMES); - } - -+/* -+ * 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 -+ * */ -+static void -+buffer_size_changed_callback(void * inClientData, -+ AudioUnit inUnit, -+ AudioUnitPropertyID inPropertyID, -+ AudioUnitScope inScope, -+ AudioUnitElement inElement) -+{ -+ cubeb_stream * stm = (cubeb_stream *)inClientData; -+ -+ AudioUnit au = inUnit; -+ AudioUnitScope au_scope = kAudioUnitScope_Input; -+ AudioUnitElement au_element = inElement; -+ const char * au_type = "output"; -+ -+ if (au == stm->input_unit) { -+ au_scope = kAudioUnitScope_Output; -+ au_type = "input"; -+ } -+ -+ switch (inPropertyID) { -+ -+ case kAudioDevicePropertyBufferFrameSize: { -+ if (inScope != au_scope) { -+ break; -+ } -+ UInt32 new_buffer_size; -+ UInt32 outSize = sizeof(UInt32); -+ OSStatus r = AudioUnitGetProperty(au, -+ kAudioDevicePropertyBufferFrameSize, -+ au_scope, -+ au_element, -+ &new_buffer_size, -+ &outSize); -+ if (r != noErr) { -+ LOG("(%p) Event: kAudioDevicePropertyBufferFrameSize: Cannot get current buffer size", stm); -+ } else { -+ LOG("(%p) Event: kAudioDevicePropertyBufferFrameSize: New %s buffer size = %d for scope %d", stm, -+ au_type, new_buffer_size, inScope); -+ } -+ stm->buffer_size_change_state = true; -+ break; -+ } -+ } -+} -+ -+enum set_buffer_size_side { -+ INPUT, -+ OUTPUT, -+}; -+ - static int --setup_audiounit_stream(cubeb_stream * stm) -+audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buffer_size_side set_side) -+{ -+ AudioUnit au = stm->output_unit; -+ AudioUnitScope au_scope = kAudioUnitScope_Input; -+ AudioUnitElement au_element = AU_OUT_BUS; -+ const char * au_type = "output"; -+ -+ if (set_side == INPUT) { -+ au = stm->input_unit; -+ au_scope = kAudioUnitScope_Output; -+ au_element = AU_IN_BUS; -+ au_type = "input"; -+ } -+ -+ uint32_t buffer_frames = 0; -+ UInt32 size = sizeof(buffer_frames); -+ int r = AudioUnitGetProperty(au, -+ kAudioDevicePropertyBufferFrameSize, -+ au_scope, -+ au_element, -+ &buffer_frames, -+ &size); -+ if (r != noErr) { -+ if (set_side == INPUT) { -+ PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r); -+ } else { -+ PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r); -+ } -+ return CUBEB_ERROR; -+ } -+ -+ if (new_size_frames == buffer_frames) { -+ LOG("(%p) No need to update %s buffer size already %u frames", stm, au_type, buffer_frames); -+ return CUBEB_OK; -+ } -+ -+ r = AudioUnitAddPropertyListener(au, -+ kAudioDevicePropertyBufferFrameSize, -+ buffer_size_changed_callback, -+ stm); -+ if (r != noErr) { -+ if (set_side == INPUT) { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r); -+ } else { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r); -+ } -+ return CUBEB_ERROR; -+ } -+ -+ stm->buffer_size_change_state = false; -+ -+ r = AudioUnitSetProperty(au, -+ kAudioDevicePropertyBufferFrameSize, -+ au_scope, -+ au_element, -+ &new_size_frames, -+ sizeof(new_size_frames)); -+ if (r != noErr) { -+ if (set_side == INPUT) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r); -+ } else { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r); -+ } -+ -+ r = AudioUnitRemovePropertyListenerWithUserData(au, -+ kAudioDevicePropertyBufferFrameSize, -+ buffer_size_changed_callback, -+ stm); -+ if (r != noErr) { -+ if (set_side == INPUT) { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r); -+ } else { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r); -+ } -+ } -+ -+ return CUBEB_ERROR; -+ } -+ -+ int count = 0; -+ while (!stm->buffer_size_change_state && count++ < 30) { -+ struct timespec req, rem; -+ req.tv_sec = 0; -+ req.tv_nsec = 100000000L; // 0.1 sec -+ if (nanosleep(&req , &rem) < 0 ) { -+ LOG("(%p) Warning: nanosleep call failed or interrupted. Remaining time %ld nano secs \n", stm, rem.tv_nsec); -+ } -+ LOG("(%p) audiounit_set_buffer_size : wait count = %d", stm, count); -+ } -+ -+ r = AudioUnitRemovePropertyListenerWithUserData(au, -+ kAudioDevicePropertyBufferFrameSize, -+ buffer_size_changed_callback, -+ stm); -+ if (r != noErr) { -+ return CUBEB_ERROR; -+ if (set_side == INPUT) { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r); -+ } else { -+ PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r); -+ } -+ } -+ -+ 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, au_type, new_size_frames); -+ return CUBEB_OK; -+} -+ -+static int -+audiounit_configure_input(cubeb_stream * stm) -+{ -+ int r = 0; -+ UInt32 size; -+ AURenderCallbackStruct aurcbs_in; -+ -+ LOG("(%p) Opening input side: rate %u, channels %u, format %d, latency in frames %u.", -+ stm, stm->input_stream_params.rate, stm->input_stream_params.channels, -+ stm->input_stream_params.format, stm->latency_frames); -+ -+ /* Get input device sample rate. */ -+ AudioStreamBasicDescription input_hw_desc; -+ size = sizeof(AudioStreamBasicDescription); -+ r = AudioUnitGetProperty(stm->input_unit, -+ kAudioUnitProperty_StreamFormat, -+ kAudioUnitScope_Input, -+ AU_IN_BUS, -+ &input_hw_desc, -+ &size); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r); -+ return CUBEB_ERROR; -+ } -+ stm->input_hw_rate = input_hw_desc.mSampleRate; -+ LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate); -+ -+ /* Set format description according to the input params. */ -+ r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params); -+ if (r != CUBEB_OK) { -+ LOG("(%p) Setting format description for input failed.", stm); -+ return r; -+ } -+ -+ // Use latency to set buffer size -+ stm->input_buffer_frames = stm->latency_frames; -+ r = audiounit_set_buffer_size(stm, stm->input_buffer_frames, INPUT); -+ if (r != CUBEB_OK) { -+ LOG("(%p) Error in change input buffer size.", stm); -+ return CUBEB_ERROR; -+ } -+ -+ AudioStreamBasicDescription src_desc = stm->input_desc; -+ /* Input AudioUnit must be configured with device's sample rate. -+ we will resample inside input callback. */ -+ src_desc.mSampleRate = stm->input_hw_rate; -+ -+ r = AudioUnitSetProperty(stm->input_unit, -+ kAudioUnitProperty_StreamFormat, -+ kAudioUnitScope_Output, -+ AU_IN_BUS, -+ &src_desc, -+ sizeof(AudioStreamBasicDescription)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r); -+ return CUBEB_ERROR; -+ } -+ -+ /* Frames per buffer in the input callback. */ -+ r = AudioUnitSetProperty(stm->input_unit, -+ kAudioUnitProperty_MaximumFramesPerSlice, -+ kAudioUnitScope_Global, -+ AU_IN_BUS, -+ &stm->input_buffer_frames, -+ sizeof(UInt32)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r); -+ return CUBEB_ERROR; -+ } -+ -+ // Input only capacity -+ unsigned int array_capacity = 1; -+ if (has_output(stm)) { -+ // Full-duplex increase capacity -+ array_capacity = 8; -+ } -+ if (audiounit_init_input_linear_buffer(stm, array_capacity) != CUBEB_OK) { -+ return CUBEB_ERROR; -+ } -+ -+ assert(stm->input_unit != NULL); -+ aurcbs_in.inputProc = audiounit_input_callback; -+ aurcbs_in.inputProcRefCon = stm; -+ -+ r = AudioUnitSetProperty(stm->input_unit, -+ kAudioOutputUnitProperty_SetInputCallback, -+ kAudioUnitScope_Global, -+ AU_OUT_BUS, -+ &aurcbs_in, -+ sizeof(aurcbs_in)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r); -+ return CUBEB_ERROR; -+ } -+ LOG("(%p) Input audiounit init successfully.", stm); -+ -+ return CUBEB_OK; -+} -+ -+static int -+audiounit_configure_output(cubeb_stream * stm) -+{ -+ int r; -+ AURenderCallbackStruct aurcbs_out; -+ UInt32 size; -+ -+ -+ LOG("(%p) Opening output side: rate %u, channels %u, format %d, latency in frames %u.", -+ stm, stm->output_stream_params.rate, stm->output_stream_params.channels, -+ stm->output_stream_params.format, stm->latency_frames); -+ -+ r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params); -+ if (r != CUBEB_OK) { -+ LOG("(%p) Could not initialize the audio stream description.", stm); -+ return r; -+ } -+ -+ /* Get output device sample rate. */ -+ AudioStreamBasicDescription output_hw_desc; -+ size = sizeof(AudioStreamBasicDescription); -+ memset(&output_hw_desc, 0, size); -+ r = AudioUnitGetProperty(stm->output_unit, -+ kAudioUnitProperty_StreamFormat, -+ kAudioUnitScope_Output, -+ AU_OUT_BUS, -+ &output_hw_desc, -+ &size); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r); -+ return CUBEB_ERROR; -+ } -+ stm->output_hw_rate = output_hw_desc.mSampleRate; -+ LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate); -+ -+ r = AudioUnitSetProperty(stm->output_unit, -+ kAudioUnitProperty_StreamFormat, -+ kAudioUnitScope_Input, -+ AU_OUT_BUS, -+ &stm->output_desc, -+ sizeof(AudioStreamBasicDescription)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r); -+ return CUBEB_ERROR; -+ } -+ -+ r = audiounit_set_buffer_size(stm, stm->latency_frames, OUTPUT); -+ if (r != CUBEB_OK) { -+ LOG("(%p) Error in change output buffer size.", stm); -+ return CUBEB_ERROR; -+ } -+ -+ /* Frames per buffer in the input callback. */ -+ r = AudioUnitSetProperty(stm->output_unit, -+ kAudioUnitProperty_MaximumFramesPerSlice, -+ kAudioUnitScope_Global, -+ AU_OUT_BUS, -+ &stm->latency_frames, -+ sizeof(UInt32)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice", r); -+ return CUBEB_ERROR; -+ } -+ -+ assert(stm->output_unit != NULL); -+ aurcbs_out.inputProc = audiounit_output_callback; -+ aurcbs_out.inputProcRefCon = stm; -+ r = AudioUnitSetProperty(stm->output_unit, -+ kAudioUnitProperty_SetRenderCallback, -+ kAudioUnitScope_Global, -+ AU_OUT_BUS, -+ &aurcbs_out, -+ sizeof(aurcbs_out)); -+ if (r != noErr) { -+ PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r); -+ return CUBEB_ERROR; -+ } -+ -+ LOG("(%p) Output audiounit init successfully.", stm); -+ return CUBEB_OK; -+} -+ -+static int -+audiounit_setup_stream(cubeb_stream * stm) - { - stm->mutex.assert_current_thread_owns(); - -- int r; -- AURenderCallbackStruct aurcbs_in; -- AURenderCallbackStruct aurcbs_out; -- UInt32 size; -- -+ int r = 0; - if (has_input(stm)) { - r = audiounit_create_unit(&stm->input_unit, true, - &stm->input_stream_params, - stm->input_device); - if (r != CUBEB_OK) { - LOG("(%p) AudioUnit creation for input failed.", stm); - return r; - } -@@ -1249,180 +1622,46 @@ setup_audiounit_stream(cubeb_stream * st - &stm->output_stream_params, - stm->output_device); - if (r != CUBEB_OK) { - LOG("(%p) AudioUnit creation for output failed.", stm); - return r; - } - } - -+ /* Latency cannot change if another stream is operating in parallel. In this case -+ * latecy is set to the other stream value. */ -+ if (stm->context->active_streams > 1) { -+ LOG("(%p) More than one active stream, use global latency.", stm); -+ stm->latency_frames = stm->context->global_latency_frames; -+ } else { -+ /* Silently clamp the latency down to the platform default, because we -+ * synthetize the clock from the callbacks, and we want the clock to update -+ * often. */ -+ stm->latency_frames = audiounit_clamp_latency(stm, stm->latency_frames); -+ assert(stm->latency_frames); // Ungly error check -+ audiounit_set_global_latency(stm, stm->latency_frames); -+ } -+ - /* Setup Input Stream! */ - if (has_input(stm)) { -- LOG("(%p) Opening input side: rate %u, channels %u, format %d, latency in frames %u.", -- stm, stm->input_stream_params.rate, stm->input_stream_params.channels, -- stm->input_stream_params.format, stm->latency_frames); -- /* Get input device sample rate. */ -- AudioStreamBasicDescription input_hw_desc; -- size = sizeof(AudioStreamBasicDescription); -- r = AudioUnitGetProperty(stm->input_unit, -- kAudioUnitProperty_StreamFormat, -- kAudioUnitScope_Input, -- AU_IN_BUS, -- &input_hw_desc, -- &size); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r); -- return CUBEB_ERROR; -- } -- stm->input_hw_rate = input_hw_desc.mSampleRate; -- LOG("(%p) Input device sampling rate: %.2f", stm, stm->input_hw_rate); -- -- /* Set format description according to the input params. */ -- r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params); -+ r = audiounit_configure_input(stm); - if (r != CUBEB_OK) { -- LOG("(%p) Setting format description for input failed.", stm); -+ LOG("(%p) Configure audiounit input failed.", stm); - return r; - } -- -- // Use latency to set buffer size -- stm->input_buffer_frames = stm->latency_frames; -- LOG("(%p) Input buffer frame count %u.", stm, unsigned(stm->input_buffer_frames)); -- r = AudioUnitSetProperty(stm->input_unit, -- kAudioDevicePropertyBufferFrameSize, -- kAudioUnitScope_Output, -- AU_IN_BUS, -- &stm->input_buffer_frames, -- sizeof(UInt32)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r); -- return CUBEB_ERROR; -- } -- -- AudioStreamBasicDescription src_desc = stm->input_desc; -- /* Input AudioUnit must be configured with device's sample rate. -- we will resample inside input callback. */ -- src_desc.mSampleRate = stm->input_hw_rate; -- -- r = AudioUnitSetProperty(stm->input_unit, -- kAudioUnitProperty_StreamFormat, -- kAudioUnitScope_Output, -- AU_IN_BUS, -- &src_desc, -- sizeof(AudioStreamBasicDescription)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat", r); -- return CUBEB_ERROR; -- } -- -- /* Frames per buffer in the input callback. */ -- r = AudioUnitSetProperty(stm->input_unit, -- kAudioUnitProperty_MaximumFramesPerSlice, -- kAudioUnitScope_Output, -- AU_IN_BUS, -- &stm->input_buffer_frames, -- sizeof(UInt32)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice", r); -- return CUBEB_ERROR; -- } -- -- // Input only capacity -- unsigned int array_capacity = 1; -- if (has_output(stm)) { -- // Full-duplex increase capacity -- array_capacity = 8; -- } -- if (audiounit_init_input_linear_buffer(stm, array_capacity) != CUBEB_OK) { -- return CUBEB_ERROR; -- } -- -- assert(stm->input_unit != NULL); -- aurcbs_in.inputProc = audiounit_input_callback; -- aurcbs_in.inputProcRefCon = stm; -- -- r = AudioUnitSetProperty(stm->input_unit, -- kAudioOutputUnitProperty_SetInputCallback, -- kAudioUnitScope_Global, -- AU_OUT_BUS, -- &aurcbs_in, -- sizeof(aurcbs_in)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r); -- return CUBEB_ERROR; -- } -- LOG("(%p) Input audiounit init successfully.", stm); - } - - /* Setup Output Stream! */ - if (has_output(stm)) { -- LOG("(%p) Opening output side: rate %u, channels %u, format %d, latency in frames %u.", -- stm, stm->output_stream_params.rate, stm->output_stream_params.channels, -- stm->output_stream_params.format, stm->latency_frames); -- r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params); -+ r = audiounit_configure_output(stm); - if (r != CUBEB_OK) { -- LOG("(%p) Could not initialize the audio stream description.", stm); -+ LOG("(%p) Configure audiounit output failed.", stm); - return r; - } -- -- /* Get output device sample rate. */ -- AudioStreamBasicDescription output_hw_desc; -- size = sizeof(AudioStreamBasicDescription); -- memset(&output_hw_desc, 0, size); -- r = AudioUnitGetProperty(stm->output_unit, -- kAudioUnitProperty_StreamFormat, -- kAudioUnitScope_Output, -- AU_OUT_BUS, -- &output_hw_desc, -- &size); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r); -- return CUBEB_ERROR; -- } -- stm->output_hw_rate = output_hw_desc.mSampleRate; -- LOG("(%p) Output device sampling rate: %.2f", stm, output_hw_desc.mSampleRate); -- -- r = AudioUnitSetProperty(stm->output_unit, -- kAudioUnitProperty_StreamFormat, -- kAudioUnitScope_Input, -- AU_OUT_BUS, -- &stm->output_desc, -- sizeof(AudioStreamBasicDescription)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r); -- return CUBEB_ERROR; -- } -- -- // Use latency to calculate buffer size -- uint32_t output_buffer_frames = stm->latency_frames; -- LOG("(%p) Output buffer frame count %u.", stm, output_buffer_frames); -- r = AudioUnitSetProperty(stm->output_unit, -- kAudioDevicePropertyBufferFrameSize, -- kAudioUnitScope_Input, -- AU_OUT_BUS, -- &output_buffer_frames, -- sizeof(output_buffer_frames)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r); -- return CUBEB_ERROR; -- } -- -- assert(stm->output_unit != NULL); -- aurcbs_out.inputProc = audiounit_output_callback; -- aurcbs_out.inputProcRefCon = stm; -- r = AudioUnitSetProperty(stm->output_unit, -- kAudioUnitProperty_SetRenderCallback, -- kAudioUnitScope_Global, -- AU_OUT_BUS, -- &aurcbs_out, -- sizeof(aurcbs_out)); -- if (r != noErr) { -- PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r); -- return CUBEB_ERROR; -- } -- LOG("(%p) Output audiounit init successfully.", stm); - } - - // Setting the latency doesn't work well for USB headsets (eg. plantronics). - // Keep the default latency for now. - #if 0 - buffer_size = latency; - - /* Get the range of latency this particular device can work with, and clamp -@@ -1535,63 +1774,60 @@ audiounit_stream_init(cubeb * context, - void * user_ptr) - { - cubeb_stream * stm; - int r; - - assert(context); - *stream = NULL; - -+ assert(latency_frames > 0); - if (context->limit_streams && context->active_streams >= CUBEB_STREAM_MAX) { - LOG("Reached the stream limit of %d", CUBEB_STREAM_MAX); - return CUBEB_ERROR; - } -- context->active_streams += 1; - - stm = (cubeb_stream *) calloc(1, sizeof(cubeb_stream)); - assert(stm); - // Placement new to call the ctors of cubeb_stream members. - new (stm) cubeb_stream(); - - /* These could be different in the future if we have both - * full-duplex stream and different devices for input vs output. */ - stm->context = context; - stm->data_callback = data_callback; - stm->state_callback = state_callback; - stm->user_ptr = user_ptr; -+ stm->latency_frames = latency_frames; - stm->device_changed_callback = NULL; - if (input_stream_params) { - stm->input_stream_params = *input_stream_params; - stm->input_device = input_device; - stm->is_default_input = input_device == nullptr || - (audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT) == - reinterpret_cast<intptr_t>(input_device)); - } - if (output_stream_params) { - stm->output_stream_params = *output_stream_params; - stm->output_device = output_device; - } - - /* Init data members where necessary */ - stm->hw_latency_frames = UINT64_MAX; - -- /* Silently clamp the latency down to the platform default, because we -- * synthetize the clock from the callbacks, and we want the clock to update -- * often. */ -- stm->latency_frames = audiounit_clamp_latency(stm, latency_frames); -- assert(latency_frames > 0); -- - stm->switching_device = false; - -+ auto_lock context_lock(context->mutex); - { - // 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 -- // `setup_audiounit_stream`. -+ // `audiounit_setup_stream`. -+ context->active_streams += 1; - auto_lock lock(stm->mutex); -- r = setup_audiounit_stream(stm); -+ r = audiounit_setup_stream(stm); - } - - if (r != CUBEB_OK) { - LOG("(%p) Could not setup the audiounit stream.", stm); - audiounit_stream_destroy(stm); - return r; - } - -@@ -1602,17 +1838,17 @@ audiounit_stream_init(cubeb * context, - } - - *stream = stm; - LOG("Cubeb stream (%p) init successful.", stm); - return CUBEB_OK; - } - - static void --close_audiounit_stream(cubeb_stream * stm) -+audiounit_close_stream(cubeb_stream *stm) - { - stm->mutex.assert_current_thread_owns(); - if (stm->input_unit) { - AudioUnitUninitialize(stm->input_unit); - AudioComponentInstanceDispose(stm->input_unit); - } - - audiounit_destroy_input_linear_buffer(stm); -@@ -1625,33 +1861,36 @@ close_audiounit_stream(cubeb_stream * st - cubeb_resampler_destroy(stm->resampler); - } - - static void - audiounit_stream_destroy(cubeb_stream * stm) - { - stm->shutdown = true; - -+ auto_lock context_locl(stm->context->mutex); - audiounit_stream_stop_internal(stm); - - { - auto_lock lock(stm->mutex); -- close_audiounit_stream(stm); -+ audiounit_close_stream(stm); - } - - #if !TARGET_OS_IPHONE - int r = audiounit_uninstall_device_changed_callback(stm); - if (r != CUBEB_OK) { - LOG("(%p) Could not uninstall the device changed callback", stm); - } - #endif - - assert(stm->context->active_streams >= 1); - stm->context->active_streams -= 1; - -+ LOG("Cubeb stream (%p) destroyed successful.", stm); -+ - stm->~cubeb_stream(); - free(stm); - } - - void - audiounit_stream_start_internal(cubeb_stream * stm) - { - OSStatus r; -@@ -1666,16 +1905,17 @@ audiounit_stream_start_internal(cubeb_st - } - - static int - audiounit_stream_start(cubeb_stream * stm) - { - stm->shutdown = false; - stm->draining = false; - -+ auto_lock context_locl(stm->context->mutex); - audiounit_stream_start_internal(stm); - - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); - - LOG("Cubeb stream (%p) started successfully.", stm); - return CUBEB_OK; - } - -@@ -1693,16 +1933,17 @@ audiounit_stream_stop_internal(cubeb_str - } - } - - static int - audiounit_stream_stop(cubeb_stream * stm) - { - stm->shutdown = true; - -+ auto_lock context_locl(stm->context->mutex); - audiounit_stream_stop_internal(stm); - - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); - - LOG("Cubeb stream (%p) stopped successfully.", stm); - return CUBEB_OK; - } - |