Bug 1380233 - Update cubeb from upstream to bb18984. r?kinetik draft
authorAlex Chronopoulos <achronop@gmail.com>
Thu, 13 Jul 2017 13:04:52 +0300
changeset 608288 c83d02da58ce7db0f335d2ce3c6696cfc06bd8f9
parent 608287 fc27e4fc79a38461033e573f3bf9d799aa558f63
child 608289 cc5bbc9502ebf362a3aae201ed9e186d3775747b
push id68229
push userachronop@gmail.com
push dateThu, 13 Jul 2017 12:20:23 +0000
reviewerskinetik
bugs1380233
milestone56.0a1
Bug 1380233 - Update cubeb from upstream to bb18984. r?kinetik MozReview-Commit-ID: FU0a9BWcOoN
media/libcubeb/README_MOZILLA
media/libcubeb/gtest/test_duplex.cpp
media/libcubeb/gtest/test_latency.cpp
media/libcubeb/gtest/test_overload_callback.cpp
media/libcubeb/gtest/test_sanity.cpp
media/libcubeb/include/cubeb.h
media/libcubeb/src/cubeb-internal.h
media/libcubeb/src/cubeb.c
media/libcubeb/src/cubeb_alsa.c
media/libcubeb/src/cubeb_audiotrack.c
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_jack.cpp
media/libcubeb/src/cubeb_mixer.cpp
media/libcubeb/src/cubeb_opensl.c
media/libcubeb/src/cubeb_pulse.c
media/libcubeb/src/cubeb_sndio.c
media/libcubeb/src/cubeb_wasapi.cpp
media/libcubeb/src/cubeb_winmm.c
--- 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 18153b9c799965b95cc411b2adbb93fefaed1cd2 (2017-06-19 19:40:57 +1200)
+The git commit ID used was bb189841de715214d88e1fa0093dc390bbf95ff4 (2017-07-12 09:27:20 +0300)
--- a/media/libcubeb/gtest/test_duplex.cpp
+++ b/media/libcubeb/gtest/test_duplex.cpp
@@ -101,17 +101,17 @@ TEST(cubeb, duplex)
   input_params.rate = 48000;
   input_params.channels = 1;
   input_params.layout = CUBEB_LAYOUT_MONO;
   output_params.format = STREAM_FORMAT;
   output_params.rate = 48000;
   output_params.channels = 2;
   output_params.layout = CUBEB_LAYOUT_STEREO;
 
-  r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
+  r = cubeb_get_min_latency(ctx, &output_params, &latency_frames);
   ASSERT_EQ(r, CUBEB_OK) << "Could not get minimal latency";
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
                         NULL, &input_params, NULL, &output_params,
                         latency_frames, data_cb_duplex, state_cb_duplex, &stream_state);
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb stream";
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
--- a/media/libcubeb/gtest/test_latency.cpp
+++ b/media/libcubeb/gtest/test_latency.cpp
@@ -34,14 +34,14 @@ TEST(cubeb, latency)
     CUBEB_SAMPLE_FLOAT32NE,
     preferred_rate,
     max_channels,
     CUBEB_LAYOUT_UNDEFINED
 #if defined(__ANDROID__)
     , CUBEB_STREAM_TYPE_MUSIC
 #endif
   };
-  r = cubeb_get_min_latency(ctx, params, &latency_frames);
+  r = cubeb_get_min_latency(ctx, &params, &latency_frames);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
     ASSERT_GT(latency_frames, 0u);
   }
 }
--- a/media/libcubeb/gtest/test_overload_callback.cpp
+++ b/media/libcubeb/gtest/test_overload_callback.cpp
@@ -64,17 +64,17 @@ TEST(cubeb, overload_callback)
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   output_params.format = STREAM_FORMAT;
   output_params.rate = 48000;
   output_params.channels = 2;
   output_params.layout = CUBEB_LAYOUT_STEREO;
 
-  r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
+  r = cubeb_get_min_latency(ctx, &output_params, &latency_frames);
   ASSERT_EQ(r, CUBEB_OK);
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb",
                         NULL, NULL, NULL, &output_params,
                         latency_frames, data_cb, state_cb, NULL);
   ASSERT_EQ(r, CUBEB_OK);
 
   std::unique_ptr<cubeb_stream, decltype(&cubeb_stream_destroy)>
--- a/media/libcubeb/gtest/test_sanity.cpp
+++ b/media/libcubeb/gtest/test_sanity.cpp
@@ -123,17 +123,17 @@ TEST(cubeb, context_variables)
 
   params.channels = STREAM_CHANNELS;
   params.format = STREAM_FORMAT;
   params.rate = STREAM_RATE;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
   params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
 #endif
-  r = cubeb_get_min_latency(ctx, params, &value);
+  r = cubeb_get_min_latency(ctx, &params, &value);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
     ASSERT_TRUE(value > 0);
   }
 
   r = cubeb_get_preferred_sample_rate(ctx, &value);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
@@ -239,16 +239,52 @@ TEST(cubeb, configure_stream)
 
   r = cubeb_stream_set_panning(stream, 0.0f);
   ASSERT_TRUE(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);
 
   cubeb_stream_destroy(stream);
   cubeb_destroy(ctx);
 }
 
+TEST(cubeb, configure_stream_undefined_layout)
+{
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+
+  r = common_init(&ctx, "test_sanity");
+  ASSERT_EQ(r, CUBEB_OK);
+  ASSERT_NE(ctx, nullptr);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = 2; // panning
+  params.layout = CUBEB_LAYOUT_UNDEFINED;
+#if defined(__ANDROID__)
+  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
+#endif
+
+  r = cubeb_stream_init(ctx, &stream, "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
+                        test_data_callback, test_state_callback, &dummy);
+  ASSERT_EQ(r, CUBEB_OK);
+  ASSERT_NE(stream, nullptr);
+
+  r = cubeb_stream_start(stream);
+  ASSERT_EQ(r, CUBEB_OK);
+
+  delay(100);
+
+  r = cubeb_stream_stop(stream);
+  ASSERT_EQ(r, CUBEB_OK);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+}
+
 static void
 test_init_start_stop_destroy_multiple_streams(int early, int delay_ms)
 {
   size_t i;
   int r;
   cubeb * ctx;
   cubeb_stream * stream[8];
   cubeb_stream_params params;
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -28,21 +28,21 @@ extern "C" {
     This example shows how to create a duplex stream that pipes the microphone
     to the speakers, with minimal latency and the proper sample-rate for the
     platform.
 
     @code
     cubeb * app_ctx;
     cubeb_init(&app_ctx, "Example Application");
     int rv;
-    int rate;
-    int latency_frames;
+    uint32_t rate;
+    uint32_t latency_frames;
     uint64_t ts;
 
-    rv = cubeb_get_min_latency(app_ctx, output_params, &latency_frames);
+    rv = cubeb_get_min_latency(app_ctx, &output_params, &latency_frames);
     if (rv != CUBEB_OK) {
       fprintf(stderr, "Could not get minimum latency");
       return rv;
     }
 
     rv = cubeb_get_preferred_sample_rate(app_ctx, output_params, &rate);
     if (rv != CUBEB_OK) {
       fprintf(stderr, "Could not get preferred sample-rate");
@@ -234,18 +234,18 @@ typedef enum {
   CUBEB_LAYOUT_3F4_LFE,
   CUBEB_LAYOUT_MAX
 } cubeb_channel_layout;
 
 /** Stream format initialization parameters. */
 typedef struct {
   cubeb_sample_format format;   /**< Requested sample format.  One of
                                      #cubeb_sample_format. */
-  unsigned int rate;            /**< Requested sample rate.  Valid range is [1000, 192000]. */
-  unsigned int channels;        /**< Requested channel count.  Valid range is [1, 8]. */
+  uint32_t rate;                /**< Requested sample rate.  Valid range is [1000, 192000]. */
+  uint32_t channels;            /**< Requested channel count.  Valid range is [1, 8]. */
   cubeb_channel_layout layout;  /**< Requested channel layout. This must be consistent with the provided channels. */
 #if defined(__ANDROID__)
   cubeb_stream_type stream_type; /**< Used to map Android audio stream types */
 #endif
 } cubeb_stream_params;
 
 /** Audio device description */
 typedef struct {
@@ -343,23 +343,23 @@ typedef struct {
   char const * vendor_name;   /**< Optional vendor name, may be NULL. */
 
   cubeb_device_type type;     /**< Type of device (Input/Output). */
   cubeb_device_state state;   /**< State of device disabled/enabled/unplugged. */
   cubeb_device_pref preferred;/**< Preferred device. */
 
   cubeb_device_fmt format;    /**< Sample format supported. */
   cubeb_device_fmt default_format; /**< The default sample format for this device. */
-  unsigned int max_channels;  /**< Channels. */
-  unsigned int default_rate;  /**< Default/Preferred sample rate. */
-  unsigned int max_rate;      /**< Maximum sample rate supported. */
-  unsigned int min_rate;      /**< Minimum sample rate supported. */
+  uint32_t max_channels;      /**< Channels. */
+  uint32_t default_rate;      /**< Default/Preferred sample rate. */
+  uint32_t max_rate;          /**< Maximum sample rate supported. */
+  uint32_t min_rate;          /**< Minimum sample rate supported. */
 
-  unsigned int latency_lo;    /**< Lowest possible latency in frames. */
-  unsigned int latency_hi;    /**< Higest possible latency in frames. */
+  uint32_t latency_lo;        /**< Lowest possible latency in frames. */
+  uint32_t latency_hi;        /**< Higest possible latency in frames. */
 } cubeb_device_info;
 
 /** Device collection.
  *  Returned by `cubeb_enumerate_devices` and destroyed by
  *  `cubeb_device_collection_destroy`. */
 typedef struct {
   cubeb_device_info * device; /**< Array of pointers to device info. */
   size_t count;               /**< Device count in collection. */
@@ -450,17 +450,17 @@ CUBEB_EXPORT int cubeb_get_max_channel_c
     @param params On some backends, the minimum achievable latency depends on
                   the characteristics of the stream.
     @param latency_frames The latency value, in frames, to pass to
                           cubeb_stream_init.
     @retval CUBEB_OK
     @retval CUBEB_ERROR_INVALID_PARAMETER
     @retval CUBEB_ERROR_NOT_SUPPORTED */
 CUBEB_EXPORT int cubeb_get_min_latency(cubeb * context,
-                                       cubeb_stream_params params,
+                                       cubeb_stream_params * params,
                                        uint32_t * latency_frames);
 
 /** Get the preferred sample rate for this backend: this is hardware and
     platform dependent, and can avoid resampling, and/or trigger fastpaths.
     @param context A pointer to the cubeb context.
     @param rate The samplerate (in Hz) the current configuration prefers.
     @retval CUBEB_OK
     @retval CUBEB_ERROR_INVALID_PARAMETER
@@ -507,17 +507,17 @@ CUBEB_EXPORT void cubeb_destroy(cubeb * 
     @retval CUBEB_ERROR_DEVICE_UNAVAILABLE */
 CUBEB_EXPORT int cubeb_stream_init(cubeb * context,
                                    cubeb_stream ** stream,
                                    char const * stream_name,
                                    cubeb_devid input_device,
                                    cubeb_stream_params * input_stream_params,
                                    cubeb_devid output_device,
                                    cubeb_stream_params * output_stream_params,
-                                   unsigned int latency_frames,
+                                   uint32_t latency_frames,
                                    cubeb_data_callback data_callback,
                                    cubeb_state_callback state_callback,
                                    void * user_ptr);
 
 /** Destroy a stream. `cubeb_stream_stop` MUST be called before destroying a
     stream.
     @param stream The stream to destroy. */
 CUBEB_EXPORT void cubeb_stream_destroy(cubeb_stream * stream);
@@ -529,16 +529,24 @@ CUBEB_EXPORT void cubeb_stream_destroy(c
 CUBEB_EXPORT int cubeb_stream_start(cubeb_stream * stream);
 
 /** Stop playback.
     @param stream
     @retval CUBEB_OK
     @retval CUBEB_ERROR */
 CUBEB_EXPORT int cubeb_stream_stop(cubeb_stream * stream);
 
+/** Reset stream to the default device.
+    @param stream
+    @retval CUBEB_OK
+    @retval CUBEB_ERROR_INVALID_PARAMETER
+    @retval CUBEB_ERROR_NOT_SUPPORTED
+    @retval CUBEB_ERROR */
+CUBEB_EXPORT int cubeb_stream_reset_default_device(cubeb_stream * stream);
+
 /** Get the current stream playback position.
     @param stream
     @param position Playback position in frames.
     @retval CUBEB_OK
     @retval CUBEB_ERROR */
 CUBEB_EXPORT int cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position);
 
 /** Get the latency for this stream, in frames. This is the number of frames
--- a/media/libcubeb/src/cubeb-internal.h
+++ b/media/libcubeb/src/cubeb-internal.h
@@ -64,16 +64,17 @@ struct cubeb_ops {
                       cubeb_stream_params * output_stream_params,
                       unsigned int latency,
                       cubeb_data_callback data_callback,
                       cubeb_state_callback state_callback,
                       void * user_ptr);
   void (* stream_destroy)(cubeb_stream * stream);
   int (* stream_start)(cubeb_stream * stream);
   int (* stream_stop)(cubeb_stream * stream);
+  int (* stream_reset_default_device)(cubeb_stream * stream);
   int (* stream_get_position)(cubeb_stream * stream, uint64_t * position);
   int (* stream_get_latency)(cubeb_stream * stream, uint32_t * latency);
   int (* stream_set_volume)(cubeb_stream * stream, float volumes);
   int (* stream_set_panning)(cubeb_stream * stream, float panning);
   int (* stream_get_current_device)(cubeb_stream * stream,
                                     cubeb_device ** const device);
   int (* stream_device_destroy)(cubeb_stream * stream,
                                 cubeb_device * device);
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -243,27 +243,27 @@ cubeb_get_max_channel_count(cubeb * cont
   if (!context->ops->get_max_channel_count) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
 
   return context->ops->get_max_channel_count(context, max_channels);
 }
 
 int
-cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, uint32_t * latency_ms)
+cubeb_get_min_latency(cubeb * context, cubeb_stream_params * params, uint32_t * latency_ms)
 {
-  if (!context || !latency_ms) {
+  if (!context || !params || !latency_ms) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
   if (!context->ops->get_min_latency) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
 
-  return context->ops->get_min_latency(context, params, latency_ms);
+  return context->ops->get_min_latency(context, *params, latency_ms);
 }
 
 int
 cubeb_get_preferred_sample_rate(cubeb * context, uint32_t * rate)
 {
   if (!context || !rate) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
@@ -367,16 +367,30 @@ cubeb_stream_stop(cubeb_stream * stream)
   if (!stream) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
   return stream->context->ops->stream_stop(stream);
 }
 
 int
+cubeb_stream_reset_default_device(cubeb_stream * stream)
+{
+  if (!stream) {
+    return CUBEB_ERROR_INVALID_PARAMETER;
+  }
+
+  if (!stream->context->ops->stream_reset_default_device) {
+    return CUBEB_ERROR_NOT_SUPPORTED;
+  }
+
+  return stream->context->ops->stream_reset_default_device(stream);
+}
+
+int
 cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position)
 {
   if (!stream || !position) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
   return stream->context->ops->stream_get_position(stream, position);
 }
--- a/media/libcubeb/src/cubeb_alsa.c
+++ b/media/libcubeb/src/cubeb_alsa.c
@@ -1356,16 +1356,17 @@ static struct cubeb_ops const alsa_ops =
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = alsa_enumerate_devices,
   .device_collection_destroy = alsa_device_collection_destroy,
   .destroy = alsa_destroy,
   .stream_init = alsa_stream_init,
   .stream_destroy = alsa_stream_destroy,
   .stream_start = alsa_stream_start,
   .stream_stop = alsa_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = alsa_stream_get_position,
   .stream_get_latency = alsa_stream_get_latency,
   .stream_set_volume = alsa_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
--- a/media/libcubeb/src/cubeb_audiotrack.c
+++ b/media/libcubeb/src/cubeb_audiotrack.c
@@ -424,16 +424,17 @@ static struct cubeb_ops const audiotrack
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = audiotrack_destroy,
   .stream_init = audiotrack_stream_init,
   .stream_destroy = audiotrack_stream_destroy,
   .stream_start = audiotrack_stream_start,
   .stream_stop = audiotrack_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = audiotrack_stream_get_position,
   .stream_get_latency = audiotrack_stream_get_latency,
   .stream_set_volume = audiotrack_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -520,18 +520,20 @@ audiounit_output_callback(void * user_pt
     if (outaff & kAudioFormatFlagIsFloat) {
       cubeb_pan_stereo_buffer_float((float*)output_buffer, outframes, panning);
     } else if (outaff & kAudioFormatFlagIsSignedInteger) {
       cubeb_pan_stereo_buffer_int((short*)output_buffer, outframes, panning);
     }
   }
 
   /* Mixing */
-  unsigned long output_buffer_length = outBufferList->mBuffers[0].mDataByteSize;
-  audiounit_mix_output_buffer(stm, output_frames, output_buffer, output_buffer_length);
+  if (stm->output_stream_params.layout != CUBEB_LAYOUT_UNDEFINED) {
+    unsigned long output_buffer_length = outBufferList->mBuffers[0].mDataByteSize;
+    audiounit_mix_output_buffer(stm, output_frames, output_buffer, output_buffer_length);
+  }
 
   return noErr;
 }
 
 extern "C" {
 int
 audiounit_init(cubeb ** context, char const * /* context_name */)
 {
@@ -2249,19 +2251,20 @@ audiounit_configure_output(cubeb_stream 
                            AU_OUT_BUS,
                            &aurcbs_out,
                            sizeof(aurcbs_out));
   if (r != noErr) {
     LOG("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv=%d", r);
     return CUBEB_ERROR;
   }
 
-  audiounit_layout_init(stm, OUTPUT);
-  audiounit_init_mixer(stm);
-
+  if (stm->output_stream_params.layout != CUBEB_LAYOUT_UNDEFINED) {
+    audiounit_layout_init(stm, OUTPUT);
+    audiounit_init_mixer(stm);
+  }
   LOG("(%p) Output audiounit init successfully.", stm);
   return CUBEB_OK;
 }
 
 static int
 audiounit_setup_stream(cubeb_stream * stm)
 {
   stm->mutex.assert_current_thread_owns();
@@ -3332,16 +3335,17 @@ cubeb_ops const audiounit_ops = {
   /*.get_preferred_channel_layout =*/ audiounit_get_preferred_channel_layout,
   /*.enumerate_devices =*/ audiounit_enumerate_devices,
   /*.device_collection_destroy =*/ audiounit_device_collection_destroy,
   /*.destroy =*/ audiounit_destroy,
   /*.stream_init =*/ audiounit_stream_init,
   /*.stream_destroy =*/ audiounit_stream_destroy,
   /*.stream_start =*/ audiounit_stream_start,
   /*.stream_stop =*/ audiounit_stream_stop,
+  /*.stream_reset_default_device =*/ nullptr,
   /*.stream_get_position =*/ audiounit_stream_get_position,
   /*.stream_get_latency =*/ audiounit_stream_get_latency,
   /*.stream_set_volume =*/ audiounit_stream_set_volume,
   /*.stream_set_panning =*/ audiounit_stream_set_panning,
   /*.stream_get_current_device =*/ audiounit_stream_get_current_device,
   /*.stream_device_destroy =*/ audiounit_stream_device_destroy,
   /*.stream_register_device_changed_callback =*/ audiounit_stream_register_device_changed_callback,
   /*.register_device_collection_changed =*/ audiounit_register_device_collection_changed
--- a/media/libcubeb/src/cubeb_jack.cpp
+++ b/media/libcubeb/src/cubeb_jack.cpp
@@ -118,16 +118,17 @@ static struct cubeb_ops const cbjack_ops
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = cbjack_enumerate_devices,
   .device_collection_destroy = cubeb_utils_default_device_collection_destroy,
   .destroy = cbjack_destroy,
   .stream_init = cbjack_stream_init,
   .stream_destroy = cbjack_stream_destroy,
   .stream_start = cbjack_stream_start,
   .stream_stop = cbjack_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = cbjack_stream_get_position,
   .stream_get_latency = cbjack_get_latency,
   .stream_set_volume = cbjack_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = cbjack_stream_get_current_device,
   .stream_device_destroy = cbjack_stream_device_destroy,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
--- a/media/libcubeb/src/cubeb_mixer.cpp
+++ b/media/libcubeb/src/cubeb_mixer.cpp
@@ -294,17 +294,17 @@ downmix_3f2(unsigned long inframes,
 /* Map the audio data by channel name. */
 template<class T>
 bool
 mix_remap(long inframes,
           T const * const in, unsigned long in_len,
           T * out, unsigned long out_len,
           cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
 {
-  assert(in_layout != out_layout);
+  assert(in_layout != out_layout && inframes >= 0);
 
   // We might overwrite the data before we copied them to the mapped index
   // (e.g. upmixing from stereo to 2F1 or mapping [L, R] to [R, L])
   if (in == out) {
     return false;
   }
 
   unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
@@ -320,25 +320,26 @@ mix_remap(long inframes,
     out_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[out_layout][i];
   }
 
   // If there is no matched channel, then do nothing.
   if (!(out_layout_mask & in_layout_mask)) {
     return false;
   }
 
-  for (long i = 0, out_index = 0; i < inframes * in_channels; i += in_channels, out_index += out_channels) {
+  for (unsigned long i = 0, out_index = 0; i < (unsigned long)inframes * in_channels; i += in_channels, out_index += out_channels) {
     for (unsigned int j = 0; j < out_channels; ++j) {
       cubeb_channel channel = CHANNEL_INDEX_TO_ORDER[out_layout][j];
       uint32_t channel_mask = 1 << channel;
       int channel_index = CHANNEL_ORDER_TO_INDEX[in_layout][channel];
-      assert((unsigned long)out_index + j < out_len);
+      assert(channel_index >= -1);
+      assert(out_index + j < out_len);
       if (in_layout_mask & channel_mask) {
-        assert((unsigned long)i + channel_index < in_len);
         assert(channel_index != -1);
+        assert(i + channel_index < in_len);
         out[out_index + j] = in[i + channel_index];
       } else {
         assert(channel_index == -1);
         out[out_index + j] = 0;
       }
     }
   }
 
@@ -348,25 +349,25 @@ mix_remap(long inframes,
 /* Drop the extra channels beyond the provided output channels. */
 template<typename T>
 void
 downmix_fallback(long inframes,
                  T const * const in, unsigned long in_len,
                  T * out, unsigned long out_len,
                  unsigned int in_channels, unsigned int out_channels)
 {
-  assert(in_channels >= out_channels);
+  assert(in_channels >= out_channels && inframes >= 0);
 
   if (in_channels == out_channels && in == out) {
     return;
   }
 
-  for (long i = 0, out_index = 0; i < inframes * in_channels; i += in_channels, out_index += out_channels) {
+  for (unsigned long i = 0, out_index = 0; i < (unsigned long)inframes * in_channels; i += in_channels, out_index += out_channels) {
     for (unsigned int j = 0; j < out_channels; ++j) {
-      assert((unsigned long)i + j < in_len && (unsigned long)out_index + j < out_len);
+      assert(i + j < in_len && out_index + j < out_len);
       out[out_index + j] = in[i + j];
     }
   }
 }
 
 
 template<typename T>
 void
@@ -485,17 +486,18 @@ cubeb_should_downmix(cubeb_stream_params
          (stream->layout == CUBEB_LAYOUT_3F2 &&      // 3f2 downmix
           (mixer->layout == CUBEB_LAYOUT_2F2_LFE ||
            mixer->layout == CUBEB_LAYOUT_3F1_LFE));
 }
 
 bool
 cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
 {
-  return cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer);
+  return stream->layout != CUBEB_LAYOUT_UNDEFINED &&
+         (cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer));
 }
 
 struct cubeb_mixer {
   virtual void mix(long frames,
                    void * input_buffer, unsigned long input_buffer_length,
                    void * output_buffer, unsigned long output_buffer_length,
                    cubeb_stream_params const * stream_params,
                    cubeb_stream_params const * mixer_params) = 0;
--- a/media/libcubeb/src/cubeb_opensl.c
+++ b/media/libcubeb/src/cubeb_opensl.c
@@ -1741,16 +1741,17 @@ static struct cubeb_ops const opensl_ops
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = opensl_destroy,
   .stream_init = opensl_stream_init,
   .stream_destroy = opensl_stream_destroy,
   .stream_start = opensl_stream_start,
   .stream_stop = opensl_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = opensl_stream_get_position,
   .stream_get_latency = opensl_stream_get_latency,
   .stream_set_volume = opensl_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -746,18 +746,19 @@ to_pulse_format(cubeb_sample_format form
 static int
 create_pa_stream(cubeb_stream * stm,
                  pa_stream ** pa_stm,
                  cubeb_stream_params * stream_params,
                  char const * stream_name)
 {
   assert(stm && stream_params);
   assert(&stm->input_stream == pa_stm || (&stm->output_stream == pa_stm &&
+         (stream_params->layout == CUBEB_LAYOUT_UNDEFINED ||
          stream_params->layout != CUBEB_LAYOUT_UNDEFINED &&
-         CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels));
+         CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels == stream_params->channels)));
   *pa_stm = NULL;
   pa_sample_spec ss;
   ss.format = to_pulse_format(stream_params->format);
   if (ss.format == PA_SAMPLE_INVALID)
     return CUBEB_ERROR_INVALID_FORMAT;
   ss.rate = stream_params->rate;
   ss.channels = stream_params->channels;
 
@@ -1493,16 +1494,17 @@ static struct cubeb_ops const pulse_ops 
   .get_preferred_channel_layout = pulse_get_preferred_channel_layout,
   .enumerate_devices = pulse_enumerate_devices,
   .device_collection_destroy = cubeb_utils_default_device_collection_destroy,
   .destroy = pulse_destroy,
   .stream_init = pulse_stream_init,
   .stream_destroy = pulse_stream_destroy,
   .stream_start = pulse_stream_start,
   .stream_stop = pulse_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = pulse_stream_get_position,
   .stream_get_latency = pulse_stream_get_latency,
   .stream_set_volume = pulse_stream_set_volume,
   .stream_set_panning = pulse_stream_set_panning,
   .stream_get_current_device = pulse_stream_get_current_device,
   .stream_device_destroy = pulse_stream_device_destroy,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = pulse_register_device_collection_changed
--- a/media/libcubeb/src/cubeb_sndio.c
+++ b/media/libcubeb/src/cubeb_sndio.c
@@ -371,16 +371,17 @@ static struct cubeb_ops const sndio_ops 
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = NULL,
   .device_collection_destroy = NULL,
   .destroy = sndio_destroy,
   .stream_init = sndio_stream_init,
   .stream_destroy = sndio_stream_destroy,
   .stream_start = sndio_stream_start,
   .stream_stop = sndio_stream_stop,
+  .stream_reset_default_device = NULL,
   .stream_get_position = sndio_stream_get_position,
   .stream_get_latency = sndio_stream_get_latency,
   .stream_set_volume = sndio_stream_set_volume,
   .stream_set_panning = NULL,
   .stream_get_current_device = NULL,
   .stream_device_destroy = NULL,
   .stream_register_device_changed_callback = NULL,
   .register_device_collection_changed = NULL
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -1758,17 +1758,18 @@ wasapi_stream_init(cubeb * context, cube
     // Make sure the layout matches the channel count.
     XASSERT(stm->input_stream_params.layout == CUBEB_LAYOUT_UNDEFINED ||
             stm->input_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->input_stream_params.layout].channels);
   }
   if (output_stream_params) {
     stm->output_stream_params = *output_stream_params;
     stm->output_device = utf8_to_wstr(reinterpret_cast<char const *>(output_device));
     // Make sure the layout matches the channel count.
-    XASSERT(stm->output_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->output_stream_params.layout].channels);
+    XASSERT(stm->output_stream_params.layout == CUBEB_LAYOUT_UNDEFINED ||
+            stm->output_stream_params.channels == CUBEB_CHANNEL_LAYOUT_MAPS[stm->output_stream_params.layout].channels);
   }
 
   switch (output_stream_params ? output_stream_params->format : input_stream_params->format) {
     case CUBEB_SAMPLE_S16NE:
       stm->bytes_per_sample = sizeof(short);
       stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_PCM;
       stm->linear_input_buffer.reset(new auto_array_wrapper_impl<short>);
       break;
@@ -2002,16 +2003,27 @@ int wasapi_stream_stop(cubeb_stream * st
     // If we could not join the thread, put the stream in error.
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 
+int wasapi_stream_reset_default_device(cubeb_stream * stm)
+{
+  XASSERT(stm && stm->reconfigure_event);
+  BOOL ok = SetEvent(stm->reconfigure_event);
+  if (!ok) {
+    LOG("SetEvent on reconfigure_event failed: %lx", GetLastError());
+    return CUBEB_ERROR;
+  }
+  return CUBEB_OK;
+}
+
 int wasapi_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   XASSERT(stm && position);
   auto_lock lock(stm->stream_reset_lock);
 
   if (!has_output(stm)) {
     return CUBEB_ERROR;
   }
@@ -2326,16 +2338,17 @@ cubeb_ops const wasapi_ops = {
   /*.get_preferred_channel_layout =*/ wasapi_get_preferred_channel_layout,
   /*.enumerate_devices =*/ wasapi_enumerate_devices,
   /*.device_collection_destroy =*/ cubeb_utils_default_device_collection_destroy,
   /*.destroy =*/ wasapi_destroy,
   /*.stream_init =*/ wasapi_stream_init,
   /*.stream_destroy =*/ wasapi_stream_destroy,
   /*.stream_start =*/ wasapi_stream_start,
   /*.stream_stop =*/ wasapi_stream_stop,
+  /*.stream_reset_default_device =*/ wasapi_stream_reset_default_device,
   /*.stream_get_position =*/ wasapi_stream_get_position,
   /*.stream_get_latency =*/ wasapi_stream_get_latency,
   /*.stream_set_volume =*/ wasapi_stream_set_volume,
   /*.stream_set_panning =*/ NULL,
   /*.stream_get_current_device =*/ NULL,
   /*.stream_device_destroy =*/ NULL,
   /*.stream_register_device_changed_callback =*/ NULL,
   /*.register_device_collection_changed =*/ NULL
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -1026,16 +1026,17 @@ static struct cubeb_ops const winmm_ops 
   /*.get_preferred_channel_layout =*/ NULL,
   /*.enumerate_devices =*/ winmm_enumerate_devices,
   /*.device_collection_destroy =*/ cubeb_utils_default_device_collection_destroy,
   /*.destroy =*/ winmm_destroy,
   /*.stream_init =*/ winmm_stream_init,
   /*.stream_destroy =*/ winmm_stream_destroy,
   /*.stream_start =*/ winmm_stream_start,
   /*.stream_stop =*/ winmm_stream_stop,
+  /*.stream_reset_default_device =*/ NULL,
   /*.stream_get_position =*/ winmm_stream_get_position,
   /*.stream_get_latency = */ winmm_stream_get_latency,
   /*.stream_set_volume =*/ winmm_stream_set_volume,
   /*.stream_set_panning =*/ NULL,
   /*.stream_get_current_device =*/ NULL,
   /*.stream_device_destroy =*/ NULL,
   /*.stream_register_device_changed_callback=*/ NULL,
   /*.register_device_collection_changed =*/ NULL