diff options
author | Paul Adenot <[email protected]> | 2018-09-11 18:25:50 +0200 |
---|---|---|
committer | Matthew Gregan <[email protected]> | 2018-09-12 09:01:12 +1200 |
commit | d6a294cde2855a2e30007403149c2dee89fec93b (patch) | |
tree | e25a75ae18b29e8cd14dd060c74039ddbcb571d0 /src/cubeb_audiounit.cpp | |
parent | 710df0b676db9bd6e2d0c4f555b68b25b81c237a (diff) | |
download | cubeb-d6a294cde2855a2e30007403149c2dee89fec93b.tar.gz cubeb-d6a294cde2855a2e30007403149c2dee89fec93b.zip |
Reinit the stream if AudioUnitRender returns kAudioUnitErr_CannotDoInCurrentContext.
This can occur using BT headset which change from A2DP profile to HFP (Hands-free Profle) or HSP (Headset Profile) when opening the microphone.
Diffstat (limited to 'src/cubeb_audiounit.cpp')
-rw-r--r-- | src/cubeb_audiounit.cpp | 64 |
1 files changed, 38 insertions, 26 deletions
diff --git a/src/cubeb_audiounit.cpp b/src/cubeb_audiounit.cpp index 21b6f53..61f398c 100644 --- a/src/cubeb_audiounit.cpp +++ b/src/cubeb_audiounit.cpp @@ -100,6 +100,16 @@ const AudioObjectPropertyAddress OUTPUT_DATA_SOURCE_PROPERTY_ADDRESS = { kAudioObjectPropertyElementMaster }; +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 */ + DEV_SELECTED_DEFAULT = 0x08, /* User selected to use the system default device */ +}; + void audiounit_stream_stop_internal(cubeb_stream * stm); void audiounit_stream_start_internal(cubeb_stream * stm); static void audiounit_close_stream(cubeb_stream *stm); @@ -108,6 +118,13 @@ 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); +static void audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags); +#endif + extern cubeb_ops const audiounit_ops; struct cubeb { @@ -152,16 +169,6 @@ to_string(io_side side) } } -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 */ - DEV_SELECTED_DEFAULT = 0x08, /* User selected to use the system default device */ -}; - struct device_info { AudioDeviceID id = kAudioObjectUnknown; device_flags_value flags = DEV_UNKNOWN; @@ -441,6 +448,9 @@ audiounit_render_input(cubeb_stream * stm, if (r != noErr) { LOG("AudioUnitRender rv=%d", r); + if (r == kAudioUnitErr_CannotDoInCurrentContext) { + audiounit_reinit_stream_async(stm, DEV_INPUT | DEV_OUTPUT); + } return r; } @@ -719,8 +729,6 @@ audiounit_get_backend_id(cubeb * /* ctx */) static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume); static int audiounit_stream_set_volume(cubeb_stream * stm, float volume); -static int audiounit_uninstall_device_changed_callback(cubeb_stream * stm); -static AudioObjectID audiounit_get_default_device_id(cubeb_device_type type); static int audiounit_set_device_info(cubeb_stream * stm, AudioDeviceID id, io_side side) @@ -832,6 +840,23 @@ audiounit_reinit_stream(cubeb_stream * stm, device_flags_value flags) return CUBEB_OK; } +static void +audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags) +{ + // 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, flags) != CUBEB_OK) { + if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) { + LOG("(%p) Could not uninstall system changed callback", stm); + } + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); + LOG("(%p) Could not reopen the stream after switching.", stm); + } + stm->switching_device = false; + }); +} + static char const * event_addr_to_string(AudioObjectPropertySelector selector) { @@ -849,8 +874,6 @@ event_addr_to_string(AudioObjectPropertySelector selector) } } -static int audiounit_uninstall_system_changed_callback(cubeb_stream * stm); - static OSStatus audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count, const AudioObjectPropertyAddress * addresses, @@ -921,18 +944,7 @@ audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count, } } - // 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, switch_side) != CUBEB_OK) { - if (audiounit_uninstall_system_changed_callback(stm) != CUBEB_OK) { - LOG("(%p) Could not uninstall system changed callback", stm); - } - stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR); - LOG("(%p) Could not reopen the stream after switching.", stm); - } - stm->switching_device = false; - }); + audiounit_reinit_stream_async(stm, switch_side); return noErr; } |