aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/cubeb_audiounit.cpp
diff options
context:
space:
mode:
authorPaul Adenot <[email protected]>2018-09-11 18:25:50 +0200
committerMatthew Gregan <[email protected]>2018-09-12 09:01:12 +1200
commitd6a294cde2855a2e30007403149c2dee89fec93b (patch)
treee25a75ae18b29e8cd14dd060c74039ddbcb571d0 /src/cubeb_audiounit.cpp
parent710df0b676db9bd6e2d0c4f555b68b25b81c237a (diff)
downloadcubeb-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.cpp64
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;
}