Bug 1342363 - Update cubeb from upstream to 25b593f. r?padenot draft
authorAlex Chronopoulos <achronop@gmail.com>
Fri, 24 Feb 2017 13:24:32 +0200
changeset 489244 ef75aa7f18b9df056495830c60cf51336c5096c7
parent 489193 be661bae6cb9a53935c5b87744bf68879d9ebcc5
child 546954 85c97e0a1d973519674474032aa40d50f17d4e41
push id46772
push userachronop@gmail.com
push dateFri, 24 Feb 2017 14:24:28 +0000
reviewerspadenot
bugs1342363
milestone54.0a1
Bug 1342363 - Update cubeb from upstream to 25b593f. r?padenot MozReview-Commit-ID: BAwQSDLJoMx
media/libcubeb/AUTHORS
media/libcubeb/README_MOZILLA
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_wasapi.cpp
--- a/media/libcubeb/AUTHORS
+++ b/media/libcubeb/AUTHORS
@@ -8,8 +8,9 @@ KO Myung-Hun <komh@chollian.net>
 Haakon Sporsheim <haakon.sporsheim@telenordigital.com>
 Alex Chronopoulos <achronop@gmail.com>
 Jan Beich <jbeich@FreeBSD.org>
 Vito Caputo <vito.caputo@coreos.com>
 Landry Breuil <landry@openbsd.org>
 Jacek Caban <jacek@codeweavers.com>
 Paul Hancock <Paul.Hancock.17041993@live.com>
 Ted Mielczarek <ted@mielczarek.org>
+Chun-Min Chang <chun.m.chang@gmail.com>
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 8977c13bf0dab9a7716501ae92ca5945fe4e1dae.
+The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e.
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -30,28 +30,22 @@
 #include "cubeb_resampler.h"
 #include "cubeb_ring_array.h"
 #include "cubeb_utils.h"
 #include <algorithm>
 #include <atomic>
 #include <vector>
 
 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
-typedef UInt32  AudioFormatFlags;
+typedef UInt32 AudioFormatFlags;
 #endif
 
 #define AU_OUT_BUS    0
 #define AU_IN_BUS     1
 
-#define fieldOffset(type, field) ((size_t) &((type *) 0)->field)
-
-#define PRINT_ERROR_CODE(str, r) do {                           \
-    LOG("System call failed: %s (rv: %d)", str, (int) r);       \
-  } while(0)
-
 const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb";
 
 #ifdef ALOGV
 #undef ALOGV
 #endif
 #define ALOGV(msg, ...) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{LOGV(msg, ##__VA_ARGS__);})
 
 #ifdef ALOG
@@ -67,44 +61,92 @@ const uint32_t SAFE_MAX_LATENCY_FRAMES =
 
 void audiounit_stream_stop_internal(cubeb_stream * stm);
 void audiounit_stream_start_internal(cubeb_stream * stm);
 static void audiounit_close_stream(cubeb_stream *stm);
 static int audiounit_setup_stream(cubeb_stream *stm);
 static int audiounit_create_unit(AudioUnit * unit, bool is_input,
                                  const cubeb_stream_params * /* stream_params */,
                                  AudioDeviceID device);
-static cubeb_channel_layout audiounit_get_channel_layout(bool preferred);
 
 extern cubeb_ops const audiounit_ops;
 
 struct cubeb {
   cubeb_ops const * ops = &audiounit_ops;
   owned_critical_section mutex;
   std::atomic<int> active_streams{ 0 };
   uint32_t global_latency_frames = 0;
   cubeb_device_collection_changed_callback collection_changed_callback = nullptr;
   void * collection_changed_user_ptr = nullptr;
   /* Differentiate input from output devices. */
   cubeb_device_type collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN;
   std::vector<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);
+  // Current used channel layout
+  cubeb_channel_layout layout;
 };
 
 struct auto_array_wrapper {
   virtual void push(void * elements, size_t length) = 0;
   virtual size_t length() = 0;
   virtual void push_silence(size_t length) = 0;
   virtual bool pop(size_t length) = 0;
   virtual void * data() = 0;
   virtual void clear() = 0;
   virtual ~auto_array_wrapper() {}
 };
 
+template <typename T>
+struct auto_array_wrapper_impl : public auto_array_wrapper {
+  explicit auto_array_wrapper_impl(uint32_t size)
+    : ar(size)
+  {}
+
+  void push(void * elements, size_t length) override {
+    auto_lock l(lock);
+    ar.push(static_cast<T *>(elements), length);
+  }
+
+  size_t length() override {
+    auto_lock l(lock);
+    return ar.length();
+  }
+
+  void push_silence(size_t length) override {
+    auto_lock l(lock);
+    ar.push_silence(length);
+  }
+
+  bool pop(size_t length) override {
+    auto_lock l(lock);
+    return ar.pop(nullptr, length);
+  }
+
+  // XXX: Taking the lock here is pointless.
+  void * data() override {
+    auto_lock l(lock);
+    return ar.data();
+  }
+
+  void clear() override {
+    auto_lock l(lock);
+    ar.clear();
+  }
+
+  ~auto_array_wrapper_impl() {
+    auto_lock l(lock);
+    ar.clear();
+  }
+
+private:
+  owned_critical_section lock;
+  auto_array<T> ar;
+};
+
 class auto_channel_layout
 {
 public:
   auto_channel_layout()
     : layout(nullptr)
   {
   }
 
@@ -143,68 +185,32 @@ private:
       free(layout);
       layout = NULL;
     }
   }
 
   AudioChannelLayout * layout;
 };
 
-template <typename T>
-struct auto_array_wrapper_impl : public auto_array_wrapper {
-  explicit auto_array_wrapper_impl(uint32_t size)
-    : ar(size)
-  {}
-
-  void push(void * elements, size_t length) override {
-    auto_lock l(lock);
-    ar.push(static_cast<T *>(elements), length);
-  }
-
-  size_t length() override {
-    auto_lock l(lock);
-    return ar.length();
-  }
-
-  void push_silence(size_t length) override {
-    auto_lock l(lock);
-    ar.push_silence(length);
-  }
-
-  bool pop(size_t length) override {
-    auto_lock l(lock);
-    return ar.pop(nullptr, length);
-  }
-
-  // XXX: Taking the lock here is pointless.
-  void * data() override {
-    auto_lock l(lock);
-    return ar.data();
-  }
-
-  void clear() override {
-    auto_lock l(lock);
-    ar.clear();
-  }
-
-  ~auto_array_wrapper_impl() {
-    auto_lock l(lock);
-    ar.clear();
-  }
-
-private:
-  owned_critical_section lock;
-  auto_array<T> ar;
-};
-
 enum io_side {
   INPUT,
   OUTPUT,
 };
 
+static char const *
+to_string(io_side side)
+{
+  switch (side) {
+  case INPUT:
+    return "input";
+  case OUTPUT:
+    return "output";
+  }
+}
+
 struct cubeb_stream {
   explicit cubeb_stream(cubeb * context);
 
   cubeb * context;
   cubeb_data_callback data_callback = nullptr;
   cubeb_state_callback state_callback = nullptr;
   cubeb_device_changed_callback device_changed_callback = nullptr;
   /* Stream creation parameters */
@@ -373,17 +379,17 @@ audiounit_render_input(cubeb_stream * st
   OSStatus r = AudioUnitRender(stm->input_unit,
                                flags,
                                tstamp,
                                bus,
                                input_frames,
                                &input_buffer_list);
 
   if (r != noErr) {
-    PRINT_ERROR_CODE("AudioUnitRender", r);
+    LOG("AudioUnitRender rv=%d", r);
     return r;
   }
 
   /* Copy input data in linear buffer. */
   stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
                                  input_frames * stm->input_desc.mChannelsPerFrame);
 
   /* Advance input frame counter. */
@@ -611,17 +617,17 @@ audiounit_get_output_device_id(AudioDevi
 
   r = AudioObjectGetPropertyData(kAudioObjectSystemObject,
                                  &output_device_address,
                                  0,
                                  NULL,
                                  &size,
                                  device_id);
   if (r != noErr) {
-    PRINT_ERROR_CODE("output_device_id", r);
+    LOG("output_device_id rv=%d", r);
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_get_input_device_id(AudioDeviceID * device_id)
@@ -796,62 +802,62 @@ audiounit_install_device_changed_callbac
     r = audiounit_get_output_device_id(&output_dev_id);
     if (r != noErr) {
       return CUBEB_ERROR;
     }
 
     r = audiounit_add_listener(stm, output_dev_id, kAudioDevicePropertyDataSource,
         kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r);
+      LOG("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource rv=%d", r);
       return CUBEB_ERROR;
     }
 
     /* 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 it
      * automatically as the default, or when another device is chosen in the
      * dropdown list. */
     r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
         kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r);
+      LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
       return CUBEB_ERROR;
     }
   }
 
   if (stm->input_unit) {
     /* This event will notify us when the data source on the input device changes. */
     AudioDeviceID input_dev_id;
     r = audiounit_get_input_device_id(&input_dev_id);
     if (r != noErr) {
       return CUBEB_ERROR;
     }
 
     r = audiounit_add_listener(stm, input_dev_id, kAudioDevicePropertyDataSource,
         kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource", r);
+      LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource rv=%d", r);
       return CUBEB_ERROR;
     }
 
     /* This event will notify us when the default input device changes. */
     r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
         kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
+      LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
       return CUBEB_ERROR;
     }
 
     /* Event to notify when the input is going away. */
     AudioDeviceID dev = stm->input_device ? stm->input_device :
                                             audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
         kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
+      LOG("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
       return CUBEB_ERROR;
     }
   }
 
   return CUBEB_OK;
 }
 
 static int
@@ -899,17 +905,17 @@ audiounit_uninstall_device_changed_callb
     }
 
     /* Event to notify when the input is going away. */
     AudioDeviceID dev = stm->input_device ? stm->input_device :
                         audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     r = audiounit_remove_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
                                   kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
+      LOG("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv=%d", r);
       return CUBEB_ERROR;
     }
   }
   return CUBEB_OK;
 }
 
 /* Get the acceptable buffer size (in frames) that this device can work with. */
 static int
@@ -934,17 +940,17 @@ audiounit_get_acceptable_latency_range(A
 
   r = AudioObjectGetPropertyData(output_device_id,
                                  &output_device_buffer_size_range,
                                  0,
                                  NULL,
                                  &size,
                                  latency_range);
   if (r != noErr) {
-    PRINT_ERROR_CODE("AudioObjectGetPropertyData/buffer size range", r);
+    LOG("AudioObjectGetPropertyData/buffer size range rv=%d", r);
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 #endif /* !TARGET_OS_IPHONE */
 
 static AudioObjectID
@@ -997,17 +1003,17 @@ audiounit_get_max_channel_count(cubeb * 
 
   r = AudioObjectGetPropertyData(output_device_id,
                                  &stream_format_address,
                                  0,
                                  NULL,
                                  &size,
                                  &stream_format);
   if (r != noErr) {
-    PRINT_ERROR_CODE("AudioObjectPropertyAddress/StreamFormat", r);
+    LOG("AudioObjectPropertyAddress/StreamFormat rv=%d", r);
     return CUBEB_ERROR;
   }
 
   *max_channels = stream_format.mChannelsPerFrame;
 #endif
   return CUBEB_OK;
 }
 
@@ -1066,27 +1072,121 @@ audiounit_get_preferred_sample_rate(cube
     return CUBEB_ERROR;
   }
 
   *rate = static_cast<uint32_t>(fsamplerate);
 #endif
   return CUBEB_OK;
 }
 
+static cubeb_channel_layout
+audiounit_convert_channel_layout(AudioChannelLayout * layout)
+{
+  if (layout->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
+    // kAudioChannelLayoutTag_UseChannelBitmap
+    // kAudioChannelLayoutTag_Mono
+    // kAudioChannelLayoutTag_Stereo
+    // ....
+    LOG("Only handle UseChannelDescriptions for now.\n");
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+
+  cubeb_channel_map cm;
+  cm.channels = layout->mNumberChannelDescriptions;
+  for (UInt32 i = 0; i < layout->mNumberChannelDescriptions; ++i) {
+    cm.map[i] = channel_label_to_cubeb_channel(layout->mChannelDescriptions[i].mChannelLabel);
+  }
+
+  return cubeb_channel_map_to_layout(&cm);
+}
+
+static cubeb_channel_layout
+audiounit_get_current_channel_layout(AudioUnit output_unit)
+{
+  OSStatus rv = noErr;
+  UInt32 size = 0;
+  rv = AudioUnitGetPropertyInfo(output_unit,
+                                kAudioUnitProperty_AudioChannelLayout,
+                                kAudioUnitScope_Output,
+                                AU_OUT_BUS,
+                                &size,
+                                nullptr);
+  if (rv != noErr) {
+    LOG("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+  assert(size > 0);
+
+  auto_channel_layout layout(size);
+  rv = AudioUnitGetProperty(output_unit,
+                            kAudioUnitProperty_AudioChannelLayout,
+                            kAudioUnitScope_Output,
+                            AU_OUT_BUS,
+                            layout.get(),
+                            &size);
+  if (rv != noErr) {
+    LOG("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout rv=%d", rv);
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+
+  return audiounit_convert_channel_layout(layout.get());
+}
+
+static cubeb_channel_layout
+audiounit_get_preferred_channel_layout()
+{
+  OSStatus rv = noErr;
+  UInt32 size = 0;
+  AudioDeviceID id;
+
+  if (audiounit_get_output_device_id(&id) != CUBEB_OK) {
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+
+  AudioObjectPropertyAddress adr = { kAudioDevicePropertyPreferredChannelLayout,
+                                     kAudioDevicePropertyScopeOutput,
+                                     kAudioObjectPropertyElementMaster };
+  rv = AudioObjectGetPropertyDataSize(id, &adr, 0, NULL, &size);
+  if (rv != noErr) {
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+  assert(size > 0);
+
+  auto_channel_layout layout(size);
+  rv = AudioObjectGetPropertyData(id, &adr, 0, NULL, &size, layout.get());
+  if (rv != noErr) {
+    return CUBEB_LAYOUT_UNDEFINED;
+  }
+
+  return audiounit_convert_channel_layout(layout.get());
+}
+
 static int
-audiounit_get_preferred_channel_layout(cubeb * /* ctx */, cubeb_channel_layout * layout)
+audiounit_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
 {
   // The preferred layout is only returned when the connected sound device
   // (e.g. ASUS Xonar U7), has preferred layout setting.
   // For default output on Mac, there is no preferred channel layout,
   // so it might return UNDEFINED.
-  // In that case, we should get the channel configuration directly.
-  *layout = audiounit_get_channel_layout(true);
+  *layout = audiounit_get_preferred_channel_layout();
+
+  // If the preferred channel layout is UNDEFINED, then we try to access the
+  // current applied channel layout.
   if (*layout == CUBEB_LAYOUT_UNDEFINED) {
-    *layout = audiounit_get_channel_layout(false);
+    // If we already have at least one cubeb stream, then the current channel
+    // layout must be updated. We can return it directly.
+    if (ctx->active_streams) {
+      return ctx->layout;
+    }
+
+    // If there is no existed stream, then we create a default ouput unit and
+    // use it to get the current used channel layout.
+    AudioUnit output_unit;
+    audiounit_create_unit(&output_unit, false, nullptr, 0);
+    *layout = audiounit_get_current_channel_layout(output_unit);
   }
 
   if (*layout == CUBEB_LAYOUT_UNDEFINED) {
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
@@ -1150,20 +1250,24 @@ audio_stream_desc_init(AudioStreamBasicD
   ss->mBytesPerPacket = ss->mBytesPerFrame * ss->mFramesPerPacket;
 
   ss->mReserved = 0;
 
   return CUBEB_OK;
 }
 
 static int
-audiounit_layout_init(AudioUnit * unit,
-                      io_side side,
-                      const cubeb_stream_params * stream_params)
+audiounit_set_channel_layout(AudioUnit unit,
+                             io_side side,
+                             const cubeb_stream_params * stream_params)
 {
+  if (side != OUTPUT) {
+    return CUBEB_ERROR;
+  }
+
   assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
   assert(stream_params->channels == CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels);
 
   OSStatus r;
   auto_channel_layout layout(sizeof(AudioChannelLayout));
 
   switch (stream_params->layout) {
     case CUBEB_LAYOUT_DUAL_MONO:
@@ -1194,45 +1298,59 @@ audiounit_layout_init(AudioUnit * unit,
     default:
       layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
       break;
   }
 
   // For those layouts that can't be matched to coreaudio's predefined layout,
   // we use customized layout.
   if (layout.get()->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
-    size_t size = fieldOffset(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
+    size_t size = offsetof(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
     layout.reset(size);
     layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
     layout.get()->mNumberChannelDescriptions = stream_params->channels;
     for (UInt32 i = 0 ; i < stream_params->channels ; ++i) {
       layout.get()->mChannelDescriptions[i].mChannelLabel =
         cubeb_channel_to_channel_label(CHANNEL_INDEX_TO_ORDER[stream_params->layout][i]);
       layout.get()->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
     }
   }
 
-  r = AudioUnitSetProperty(*unit,
+  r = AudioUnitSetProperty(unit,
                            kAudioUnitProperty_AudioChannelLayout,
-                           side == INPUT ? kAudioUnitScope_Output : kAudioUnitScope_Input,
-                           side == INPUT ? AU_IN_BUS : AU_OUT_BUS,
+                           kAudioUnitScope_Input,
+                           AU_OUT_BUS,
                            layout.get(),
                            layout.size());
   if (r != noErr) {
-    if (side == INPUT) {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_AudioChannelLayout", r);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_AudioChannelLayout", r);
-    }
+    LOG("AudioUnitSetProperty/%s/kAudioUnitProperty_AudioChannelLayout rv=%d", to_string(side), r);
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 
+void
+audiounit_layout_init(cubeb_stream * stm, io_side side)
+{
+  // We currently don't support the input layout setting.
+  if (side == INPUT) {
+    return;
+  }
+
+  audiounit_set_channel_layout(stm->output_unit, OUTPUT, &stm->output_stream_params);
+
+  // Update the current used channel layout for the cubeb context.
+  // Notice that this channel layout may be different from the layout we set above,
+  // because OSX doesn't return error when the output device can NOT provide
+  // our desired layout. Thus, we update the layout evertime when the cubeb_stream
+  // is created and use it when we need to mix audio data.
+  stm->context->layout = audiounit_get_current_channel_layout(stm->output_unit);
+}
+
 static int
 audiounit_create_unit(AudioUnit * unit,
                       bool is_input,
                       const cubeb_stream_params * /* stream_params */,
                       AudioDeviceID device)
 {
   AudioComponentDescription desc;
   AudioComponent comp;
@@ -1262,51 +1380,51 @@ audiounit_create_unit(AudioUnit * unit,
   comp = AudioComponentFindNext(NULL, &desc);
   if (comp == NULL) {
     LOG("Could not find matching audio hardware.");
     return CUBEB_ERROR;
   }
 
   rv = AudioComponentInstanceNew(comp, unit);
   if (rv != noErr) {
-    PRINT_ERROR_CODE("AudioComponentInstanceNew", rv);
+    LOG("AudioComponentInstanceNew rv=%d", rv);
     return CUBEB_ERROR;
   }
 
   if (!use_default_output) {
     enable = 1;
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
                               is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
                               is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
     if (rv != noErr) {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
+      LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
       return CUBEB_ERROR;
     }
 
     enable = 0;
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
                               is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
                               is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
     if (rv != noErr) {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
+      LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO rv=%d", rv);
       return CUBEB_ERROR;
     }
 
     if (device == 0) {
       assert(is_input);
       devid = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     } else {
       devid = device;
     }
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
                               kAudioUnitScope_Global,
                               is_input ? AU_IN_BUS : AU_OUT_BUS,
                               &devid, sizeof(AudioDeviceID));
     if (rv != noErr) {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
+      LOG("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice rv=%d", rv);
       return CUBEB_ERROR;
     }
   }
 
   return CUBEB_OK;
 }
 
 static int
@@ -1341,34 +1459,34 @@ audiounit_clamp_latency(cubeb_stream * s
   if (stm->output_unit) {
     r = AudioUnitGetProperty(stm->output_unit,
                             kAudioDevicePropertyBufferFrameSize,
                             kAudioUnitScope_Output,
                             AU_OUT_BUS,
                             &output_buffer_size,
                             &size);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
+      LOG("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize rv=%d", r);
       return 0;
     }
 
     output_buffer_size = std::max(std::min<uint32_t>(output_buffer_size, SAFE_MAX_LATENCY_FRAMES),
                                   SAFE_MIN_LATENCY_FRAMES);
   }
 
   UInt32 input_buffer_size = 0;
   if (stm->input_unit) {
     r = AudioUnitGetProperty(stm->input_unit,
                             kAudioDevicePropertyBufferFrameSize,
                             kAudioUnitScope_Input,
                             AU_IN_BUS,
                             &input_buffer_size,
                             &size);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
+      LOG("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize rv=%d", r);
       return 0;
     }
 
     input_buffer_size = std::max(std::min<uint32_t>(input_buffer_size, SAFE_MAX_LATENCY_FRAMES),
                                  SAFE_MIN_LATENCY_FRAMES);
   }
 
   // Every following active streams can only set smaller latency
@@ -1393,26 +1511,26 @@ audiounit_clamp_latency(cubeb_stream * s
  * - 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)
+                             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";
+  char const * au_type = "output";
 
   if (au == stm->input_unit) {
     au_scope = kAudioUnitScope_Output;
     au_type = "input";
   }
 
   switch (inPropertyID) {
 
@@ -1441,85 +1559,67 @@ buffer_size_changed_callback(void * inCl
 }
 
 static int
 audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side side)
 {
   AudioUnit au = stm->output_unit;
   AudioUnitScope au_scope = kAudioUnitScope_Input;
   AudioUnitElement au_element = AU_OUT_BUS;
-  const char * au_type = "output";
 
   if (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 (side == INPUT) {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
-    }
+    LOG("AudioUnitGetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), 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);
+    LOG("(%p) No need to update %s buffer size already %u frames", stm, to_string(side), buffer_frames);
     return CUBEB_OK;
   }
 
   r = AudioUnitAddPropertyListener(au,
                                    kAudioDevicePropertyBufferFrameSize,
                                    buffer_size_changed_callback,
                                    stm);
   if (r != noErr) {
-    if (side == INPUT) {
-      PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
-    }
+    LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), 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 (side == INPUT) {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
-    }
+    LOG("AudioUnitSetProperty/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
 
     r = AudioUnitRemovePropertyListenerWithUserData(au,
                                                     kAudioDevicePropertyBufferFrameSize,
                                                     buffer_size_changed_callback,
                                                     stm);
     if (r != noErr) {
-      if (side == INPUT) {
-        PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
-      } else {
-        PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
-      }
+      LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
     }
 
     return CUBEB_ERROR;
   }
 
   int count = 0;
   while (!stm->buffer_size_change_state && count++ < 30) {
     struct timespec req, rem;
@@ -1531,30 +1631,26 @@ audiounit_set_buffer_size(cubeb_stream *
     LOG("(%p) audiounit_set_buffer_size : wait count = %d", stm, count);
   }
 
   r = AudioUnitRemovePropertyListenerWithUserData(au,
                                                   kAudioDevicePropertyBufferFrameSize,
                                                   buffer_size_changed_callback,
                                                   stm);
   if (r != noErr) {
-    if (side == INPUT) {
-      PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
-    }
+    LOG("AudioUnitAddPropertyListener/%s/kAudioDevicePropertyBufferFrameSize rv=%d", to_string(side), r);
     return CUBEB_ERROR;
   }
 
   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);
+  LOG("(%p) %s buffer size changed to %u frames.", stm, to_string(side), new_size_frames);
   return CUBEB_OK;
 }
 
 static int
 audiounit_configure_input(cubeb_stream * stm)
 {
   int r = 0;
   UInt32 size;
@@ -1569,17 +1665,17 @@ audiounit_configure_input(cubeb_stream *
   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);
+    LOG("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", 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) {
@@ -1602,29 +1698,29 @@ audiounit_configure_input(cubeb_stream *
 
   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);
+    LOG("AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat rv=%d", 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);
+    LOG("AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", r);
     return CUBEB_ERROR;
   }
 
   // Input only capacity
   unsigned int array_capacity = 1;
   if (has_output(stm)) {
     // Full-duplex increase capacity
     array_capacity = 8;
@@ -1639,17 +1735,17 @@ audiounit_configure_input(cubeb_stream *
 
   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);
+    LOG("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback rv=%d", r);
     return CUBEB_ERROR;
   }
   LOG("(%p) Input audiounit init successfully.", stm);
 
   return CUBEB_OK;
 }
 
 static int
@@ -1676,30 +1772,30 @@ audiounit_configure_output(cubeb_stream 
   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/kAudioUnitProperty_StreamFormat", r);
+    LOG("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", 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);
+    LOG("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat rv=%d", 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;
   }
@@ -1707,35 +1803,35 @@ audiounit_configure_output(cubeb_stream 
   /* 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);
+    LOG("AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice rv=%d", 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);
+    LOG("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv=%d", r);
     return CUBEB_ERROR;
   }
 
-  audiounit_layout_init(&stm->output_unit, OUTPUT, &stm->output_stream_params);
+  audiounit_layout_init(stm, OUTPUT);
 
   LOG("(%p) Output audiounit init successfully.", stm);
   return CUBEB_OK;
 }
 
 static int
 audiounit_setup_stream(cubeb_stream * stm)
 {
@@ -1867,25 +1963,25 @@ audiounit_setup_stream(cubeb_stream * st
   if (!stm->resampler) {
     LOG("(%p) Could not create resampler.", stm);
     return CUBEB_ERROR;
   }
 
   if (stm->input_unit != NULL) {
     r = AudioUnitInitialize(stm->input_unit);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitInitialize/input", r);
+      LOG("AudioUnitInitialize/input rv=%d", r);
       return CUBEB_ERROR;
     }
   }
 
   if (stm->output_unit != NULL) {
     r = AudioUnitInitialize(stm->output_unit);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitInitialize/output", r);
+      LOG("AudioUnitInitialize/output rv=%d", r);
       return CUBEB_ERROR;
     }
   }
 
   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.
@@ -2117,41 +2213,41 @@ audiounit_stream_get_latency(cubeb_strea
     size = sizeof(unit_latency_sec);
     r = AudioUnitGetProperty(stm->output_unit,
                              kAudioUnitProperty_Latency,
                              kAudioUnitScope_Global,
                              0,
                              &unit_latency_sec,
                              &size);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_Latency", r);
+      LOG("AudioUnitGetProperty/kAudioUnitProperty_Latency rv=%d", r);
       return CUBEB_ERROR;
     }
 
     size = sizeof(device_latency_frames);
     r = AudioObjectGetPropertyData(output_device_id,
                                    &latency_address,
                                    0,
                                    NULL,
                                    &size,
                                    &device_latency_frames);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitGetPropertyData/latency_frames", r);
+      LOG("AudioUnitGetPropertyData/latency_frames rv=%d", r);
       return CUBEB_ERROR;
     }
 
     size = sizeof(device_safety_offset);
     r = AudioObjectGetPropertyData(output_device_id,
                                    &safety_offset_address,
                                    0,
                                    NULL,
                                    &size,
                                    &device_safety_offset);
     if (r != noErr) {
-      PRINT_ERROR_CODE("AudioUnitGetPropertyData/safety_offset", r);
+      LOG("AudioUnitGetPropertyData/safety_offset rv=%d", r);
       return CUBEB_ERROR;
     }
 
     /* This part is fixed and depend on the stream parameter and the hardware. */
     stm->hw_latency_frames =
       static_cast<uint32_t>(unit_latency_sec * stm->output_desc.mSampleRate)
       + device_latency_frames
       + device_safety_offset;
@@ -2168,17 +2264,17 @@ int audiounit_stream_set_volume(cubeb_st
   OSStatus r;
 
   r = AudioUnitSetParameter(stm->output_unit,
                             kHALOutputParam_Volume,
                             kAudioUnitScope_Global,
                             0, volume, 0);
 
   if (r != noErr) {
-    PRINT_ERROR_CODE("AudioUnitSetParameter/kHALOutputParam_Volume", r);
+    LOG("AudioUnitSetParameter/kHALOutputParam_Volume rv=%d", r);
     return CUBEB_ERROR;
   }
   return CUBEB_OK;
 }
 
 int audiounit_stream_set_panning(cubeb_stream * stm, float panning)
 {
   if (stm->output_desc.mChannelsPerFrame > 2) {
@@ -2524,17 +2620,17 @@ audiounit_create_device_from_hwdev(Audio
   latency = audiounit_get_device_presentation_latency(devid, adr.mScope);
 
   adr.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
   size = sizeof(AudioValueRange);
   if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &range) == noErr) {
     ret->latency_lo = latency + range.mMinimum;
     ret->latency_hi = latency + range.mMaximum;
   } else {
-    ret->latency_lo = 10 * ret->default_rate / 1000;  /* Default to  10ms */
+    ret->latency_lo = 10 * ret->default_rate / 1000;  /* Default to 10ms */
     ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
   }
 
   return ret;
 }
 
 static int
 audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
@@ -2717,79 +2813,16 @@ int audiounit_register_device_collection
                                         collection_changed_callback,
                                         user_ptr);
   } else {
     ret = audiounit_remove_device_listener(context);
   }
   return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR;
 }
 
-static cubeb_channel_layout
-audiounit_get_channel_layout(bool preferred)
-{
-  OSStatus rv = noErr;
-
-  // Get the default ouput unit
-  AudioUnit output_unit;
-  audiounit_create_unit(&output_unit, false, nullptr, 0);
-
-  // Get the channel layout
-  UInt32 size = 0;
-  rv = AudioUnitGetPropertyInfo(output_unit,
-                                preferred ? kAudioDevicePropertyPreferredChannelLayout :
-                                            kAudioUnitProperty_AudioChannelLayout,
-                                kAudioUnitScope_Output,
-                                AU_OUT_BUS,
-                                &size,
-                                nullptr);
-  if (rv != noErr) {
-    if (preferred) {
-      PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout", rv);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout", rv);
-    }
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-  assert(size > 0);
-
-  auto_channel_layout layout(size);
-  rv = AudioUnitGetProperty(output_unit,
-                            preferred ? kAudioDevicePropertyPreferredChannelLayout :
-                                        kAudioUnitProperty_AudioChannelLayout,
-                            kAudioUnitScope_Output,
-                            AU_OUT_BUS,
-                            layout.get(),
-                            &size);
-  if (rv != noErr) {
-    if (preferred) {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout", rv);
-    } else {
-      PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout", rv);
-    }
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-
-  if (layout.get()->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
-    // kAudioChannelLayoutTag_UseChannelBitmap
-    // kAudioChannelLayoutTag_Mono
-    // kAudioChannelLayoutTag_Stereo
-    // ....
-    LOG("Only handle UseChannelDescriptions for now.\n");
-    return CUBEB_LAYOUT_UNDEFINED;
-  }
-
-  cubeb_channel_map cm;
-  cm.channels = layout.get()->mNumberChannelDescriptions;
-  for (UInt32 i = 0; i < layout.get()->mNumberChannelDescriptions; ++i) {
-    cm.map[i] = channel_label_to_cubeb_channel(layout.get()->mChannelDescriptions[i].mChannelLabel);
-  }
-
-  return cubeb_channel_map_to_layout(&cm);
-}
-
 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_preferred_channel_layout =*/ audiounit_get_preferred_channel_layout,
   /*.enumerate_devices =*/ audiounit_enumerate_devices,
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -852,16 +852,21 @@ wasapi_stream_render_loop(LPVOID stream)
   /* We could consider using "Pro Audio" here for WebAudio and
      maybe WebRTC. */
   mmcss_handle = AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
   if (!mmcss_handle) {
     /* This is not fatal, but we might glitch under heavy load. */
     LOG("Unable to use mmcss to bump the render thread priority: %lx", GetLastError());
   }
 
+  // This has already been nulled out, simply exit.
+  if (!emergency_bailout) {
+    is_playing = false;
+  }
+
   /* WaitForMultipleObjects timeout can trigger in cases where we don't want to
      treat it as a timeout, such as across a system sleep/wake cycle.  Trigger
      the timeout error handling only when the timeout_limit is reached, which is
      reset on each successful loop. */
   unsigned timeout_count = 0;
   const unsigned timeout_limit = 5;
   while (is_playing) {
     DWORD waitResult = WaitForMultipleObjects(ARRAY_LENGTH(wait_array),
@@ -1161,22 +1166,26 @@ bool stop_and_join_render_thread(cubeb_s
 
   /* Wait five seconds for the rendering thread to return. It's supposed to
    * check its event loop very often, five seconds is rather conservative. */
   DWORD r = WaitForSingleObject(stm->thread, 5000);
   if (r == WAIT_TIMEOUT) {
     /* Something weird happened, leak the thread and continue the shutdown
      * process. */
     *(stm->emergency_bailout) = true;
+    // We give the ownership to the rendering thread.
+    stm->emergency_bailout = nullptr;
     LOG("Destroy WaitForSingleObject on thread timed out,"
         " leaking the thread: %lx", GetLastError());
     rv = false;
   }
   if (r == WAIT_FAILED) {
     *(stm->emergency_bailout) = true;
+    // We give the ownership to the rendering thread.
+    stm->emergency_bailout = nullptr;
     LOG("Destroy WaitForSingleObject on thread failed: %lx", GetLastError());
     rv = false;
   }
 
 
   // Only attempts to close and null out the thread and event if the
   // WaitForSingleObject above succeeded, so that calling this function again
   // attemps to clean up the thread and event each time.
@@ -1594,18 +1603,25 @@ int setup_wasapi_stream(cubeb_stream * s
                                       stm->input_available_event,
                                       stm->capture_client,
                                       &stm->input_mix_params);
 
     // We initializing an input stream, buffer ahead two buffers worth of silence.
     // This delays the input side slightly, but allow to not glitch when no input
     // is available when calling into the resampler to call the callback: the input
     // refill event will be set shortly after to compensate for this lack of data.
+    // In debug, four buffers are used, to avoid tripping up assertions down the line.
+#if !defined(NDEBUG)
+    const int silent_buffer_count = 2;
+#else
+    const int silent_buffer_count = 4;
+#endif
     stm->linear_input_buffer.push_silence(stm->input_buffer_frame_count *
-                                          stm->input_stream_params.channels * 2);
+                                          stm->input_stream_params.channels *
+                                          silent_buffer_count);
 
     if (rv != CUBEB_OK) {
       LOG("Failure to open the input side.");
       return rv;
     }
   }
 
   if (has_output(stm)) {
@@ -1816,19 +1832,16 @@ void wasapi_stream_destroy(cubeb_stream 
   XASSERT(stm);
 
   // Only free stm->emergency_bailout if we could join the thread.
   // If we could not join the thread, stm->emergency_bailout is true
   // and is still alive until the thread wakes up and exits cleanly.
   if (stop_and_join_render_thread(stm)) {
     delete stm->emergency_bailout.load();
     stm->emergency_bailout = nullptr;
-  } else {
-    // If we're leaking, it must be that this is true.
-    XASSERT(*(stm->emergency_bailout));
   }
 
   unregister_notification_client(stm);
 
   CloseHandle(stm->reconfigure_event);
   CloseHandle(stm->refill_event);
   CloseHandle(stm->input_available_event);
 
@@ -1880,21 +1893,21 @@ int stream_start_one_side(cubeb_stream *
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 
 int wasapi_stream_start(cubeb_stream * stm)
 {
+  auto_lock lock(stm->stream_reset_lock);
+
   XASSERT(stm && !stm->thread && !stm->shutdown_event);
   XASSERT(stm->output_client || stm->input_client);
 
-  auto_lock lock(stm->stream_reset_lock);
-
   stm->emergency_bailout = new std::atomic<bool>(false);
 
   if (stm->output_client) {
     int rv = stream_start_one_side(stm, OUTPUT);
     if (rv != CUBEB_OK) {
       return rv;
     }
   }
@@ -1946,16 +1959,17 @@ int wasapi_stream_stop(cubeb_stream * st
         return CUBEB_ERROR;
       }
     }
 
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
   }
 
   if (stop_and_join_render_thread(stm)) {
+    // This is null if we've given the pointer to the other thread
     if (stm->emergency_bailout.load()) {
       delete stm->emergency_bailout.load();
       stm->emergency_bailout = nullptr;
     }
   }
 
   return CUBEB_OK;
 }