Bug 1367646 - Update cubeb from upstream to 087dc94. r=kinetik
authorDan Glastonbury <dan.glastonbury@gmail.com>
Thu, 25 May 2017 14:45:04 +1000
changeset 361148 e21dcef641e4e50a5865b20757690bca2b464f65
parent 361147 936b9481291345714e4d8336dbd3b4167fc5f3ac
child 361149 75eef8b3b1a55fda2faafba899062fc05e427bf6
push id43656
push userdglastonbury@mozilla.com
push dateTue, 30 May 2017 00:38:06 +0000
treeherderautoland@75eef8b3b1a5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1367646
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1367646 - Update cubeb from upstream to 087dc94. r=kinetik MozReview-Commit-ID: E1D2XCtugqW
media/libcubeb/README_MOZILLA
media/libcubeb/gtest/common.h
media/libcubeb/gtest/test_audio.cpp
media/libcubeb/gtest/test_devices.cpp
media/libcubeb/gtest/test_duplex.cpp
media/libcubeb/gtest/test_latency.cpp
media/libcubeb/gtest/test_mixer.cpp
media/libcubeb/gtest/test_overload_callback.cpp
media/libcubeb/gtest/test_record.cpp
media/libcubeb/gtest/test_sanity.cpp
media/libcubeb/gtest/test_tone.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_audiounit.cpp
media/libcubeb/src/cubeb_jack.cpp
media/libcubeb/src/cubeb_mixer.cpp
media/libcubeb/src/cubeb_mixer.h
media/libcubeb/src/cubeb_pulse.c
media/libcubeb/src/cubeb_sndio.c
media/libcubeb/src/cubeb_utils.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 96cdb173f86dfc86cbd21d097b24ec1e256d69fc (2017-05-22 11:55:15 +0300)
+The git commit ID used was 087dc942a9a3bb5cbb88e3763cde7fe709db99e9 (2017-05-29 15:51:19 +1200)
--- a/media/libcubeb/gtest/common.h
+++ b/media/libcubeb/gtest/common.h
@@ -65,47 +65,69 @@ layout_info const layout_infos[CUBEB_LAY
   { "3f2",            5,  CUBEB_LAYOUT_3F2 },
   { "3f2 lfe",        6,  CUBEB_LAYOUT_3F2_LFE },
   { "3f3r lfe",       7,  CUBEB_LAYOUT_3F3R_LFE },
   { "3f4 lfe",        8,  CUBEB_LAYOUT_3F4_LFE }
 };
 
 int has_available_input_device(cubeb * ctx)
 {
-  cubeb_device_collection * devices;
+  cubeb_device_collection devices;
   int input_device_available = 0;
   int r;
   /* Bail out early if the host does not have input devices. */
   r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_INPUT, &devices);
   if (r != CUBEB_OK) {
     fprintf(stderr, "error enumerating devices.");
     return 0;
   }
 
-  if (devices->count == 0) {
+  if (devices.count == 0) {
     fprintf(stderr, "no input device available, skipping test.\n");
-    cubeb_device_collection_destroy(ctx, devices);
+    cubeb_device_collection_destroy(ctx, &devices);
     return 0;
   }
 
-  for (uint32_t i = 0; i < devices->count; i++) {
-    input_device_available |= (devices->device[i]->state ==
+  for (uint32_t i = 0; i < devices.count; i++) {
+    input_device_available |= (devices.device[i].state ==
                                CUBEB_DEVICE_STATE_ENABLED);
   }
 
   if (!input_device_available) {
     fprintf(stderr, "there are input devices, but they are not "
         "available, skipping\n");
   }
 
-  cubeb_device_collection_destroy(ctx, devices);
+  cubeb_device_collection_destroy(ctx, &devices);
   return !!input_device_available;
 }
 
 void print_log(const char * msg, ...)
 {
   va_list args;
   va_start(args, msg);
   vprintf(msg, args);
   va_end(args);
 }
 
+/** Initialize cubeb with backend override.
+ *  Create call cubeb_init passing value for CUBEB_BACKEND env var as
+ *  override. */
+int common_init(cubeb ** ctx, char const * ctx_name)
+{
+  int r;
+  char const * backend;
+  char const * ctx_backend;
+
+  backend = getenv("CUBEB_BACKEND");
+  r = cubeb_init(ctx, ctx_name, backend);
+  if (r == CUBEB_OK && backend) {
+    ctx_backend = cubeb_get_backend_id(*ctx);
+    if (strcmp(backend, ctx_backend) != 0) {
+      fprintf(stderr, "Requested backend `%s', got `%s'\n",
+              backend, ctx_backend);
+    }
+  }
+
+  return r;
+}
+
 #endif /* TEST_COMMON */
--- a/media/libcubeb/gtest/test_audio.cpp
+++ b/media/libcubeb/gtest/test_audio.cpp
@@ -95,17 +95,17 @@ int supports_channel_count(string backen
 }
 
 int run_test(int num_channels, layout_info layout, int sampling_rate, int is_float)
 {
   int r = CUBEB_OK;
 
   cubeb *ctx = NULL;
 
-  r = cubeb_init(&ctx, "Cubeb audio test: channels", NULL);
+  r = common_init(&ctx, "Cubeb audio test: channels");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
     return r;
   }
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   const char * backend_id = cubeb_get_backend_id(ctx);
@@ -145,17 +145,17 @@ int run_test(int num_channels, layout_in
 }
 
 int run_panning_volume_test(int is_float)
 {
   int r = CUBEB_OK;
 
   cubeb *ctx = NULL;
 
-  r = cubeb_init(&ctx, "Cubeb audio test", NULL);
+  r = common_init(&ctx, "Cubeb audio test");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
     return r;
   }
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
--- a/media/libcubeb/gtest/test_devices.cpp
+++ b/media/libcubeb/gtest/test_devices.cpp
@@ -8,16 +8,17 @@
 /* libcubeb enumerate device test/example.
  * Prints out a list of devices enumerated. */
 #include "gtest/gtest.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <memory>
 #include "cubeb/cubeb.h"
+#include "common.h"
 
 static void
 print_device_info(cubeb_device_info * info, FILE * f)
 {
   char devfmts[64] = "";
   const char * devtype, * devstate, * devdeffmt;
 
   switch (info->type) {
@@ -96,48 +97,71 @@ print_device_info(cubeb_device_info * in
 }
 
 static void
 print_device_collection(cubeb_device_collection * collection, FILE * f)
 {
   uint32_t i;
 
   for (i = 0; i < collection->count; i++)
-    print_device_info(collection->device[i], f);
+    print_device_info(&collection->device[i], f);
+}
+
+TEST(cubeb, destroy_default_collection)
+{
+  int r;
+  cubeb * ctx = NULL;
+  cubeb_device_collection collection{ nullptr, 0 };
+
+  r = common_init(&ctx, "Cubeb audio test");
+  ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
+
+  std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
+    cleanup_cubeb_at_exit(ctx, cubeb_destroy);
+
+  ASSERT_EQ(collection.device, nullptr);
+  ASSERT_EQ(collection.count, (size_t) 0);
+
+  r = cubeb_device_collection_destroy(ctx, &collection);
+  if (r != CUBEB_ERROR_NOT_SUPPORTED) {
+    ASSERT_EQ(r, CUBEB_OK);
+    ASSERT_EQ(collection.device, nullptr);
+    ASSERT_EQ(collection.count, (size_t) 0);
+  }
 }
 
 TEST(cubeb, enumerate_devices)
 {
   int r;
   cubeb * ctx = NULL;
-  cubeb_device_collection * collection = NULL;
+  cubeb_device_collection collection;
 
-  r = cubeb_init(&ctx, "Cubeb audio test", NULL);
+  r = common_init(&ctx, "Cubeb audio test");
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   fprintf(stdout, "Enumerating input devices for backend %s\n",
       cubeb_get_backend_id(ctx));
 
   r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_INPUT, &collection);
   if (r == CUBEB_ERROR_NOT_SUPPORTED) {
     fprintf(stderr, "Device enumeration not supported"
                     " for this backend, skipping this test.\n");
     r = CUBEB_OK;
   }
   ASSERT_EQ(r, CUBEB_OK) << "Error enumerating devices " << r;
 
-  fprintf(stdout, "Found %u input devices\n", collection->count);
-  print_device_collection(collection, stdout);
-  cubeb_device_collection_destroy(ctx, collection);
+  fprintf(stdout, "Found %zu input devices\n", collection.count);
+  print_device_collection(&collection, stdout);
+  cubeb_device_collection_destroy(ctx, &collection);
 
   fprintf(stdout, "Enumerating output devices for backend %s\n",
           cubeb_get_backend_id(ctx));
 
   r = cubeb_enumerate_devices(ctx, CUBEB_DEVICE_TYPE_OUTPUT, &collection);
   ASSERT_EQ(r, CUBEB_OK) << "Error enumerating devices " << r;
 
-  fprintf(stdout, "Found %u output devices\n", collection->count);
-  print_device_collection(collection, stdout);
-  cubeb_device_collection_destroy(ctx, collection);
+  fprintf(stdout, "Found %zu output devices\n", collection.count);
+  print_device_collection(&collection, stdout);
+  cubeb_device_collection_destroy(ctx, &collection);
 }
--- a/media/libcubeb/gtest/test_duplex.cpp
+++ b/media/libcubeb/gtest/test_duplex.cpp
@@ -78,17 +78,17 @@ TEST(cubeb, duplex)
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params input_params;
   cubeb_stream_params output_params;
   int r;
   user_state_duplex stream_state = { false };
   uint32_t latency_frames = 0;
 
-  r = cubeb_init(&ctx, "Cubeb duplex example", NULL);
+  r = common_init(&ctx, "Cubeb duplex example");
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   /* This test needs an available input device, skip it if this host does not
    * have one. */
   if (!has_available_input_device(ctx)) {
--- a/media/libcubeb/gtest/test_latency.cpp
+++ b/media/libcubeb/gtest/test_latency.cpp
@@ -1,23 +1,23 @@
 #include "gtest/gtest.h"
 #include <stdlib.h>
 #include <memory>
 #include "cubeb/cubeb.h"
+#include "common.h"
 
 TEST(cubeb, latency)
 {
   cubeb * ctx = NULL;
   int r;
   uint32_t max_channels;
   uint32_t preferred_rate;
   uint32_t latency_frames;
-  cubeb_channel_layout layout;
 
-  r = cubeb_init(&ctx, "Cubeb audio test", NULL);
+  r = common_init(&ctx, "Cubeb audio test");
   ASSERT_EQ(r, CUBEB_OK);
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   r = cubeb_get_max_channel_count(ctx, &max_channels);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
@@ -25,25 +25,21 @@ TEST(cubeb, latency)
   }
 
   r = cubeb_get_preferred_sample_rate(ctx, &preferred_rate);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
     ASSERT_GT(preferred_rate, 0u);
   }
 
-  r = cubeb_get_preferred_channel_layout(ctx, &layout);
-  ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED ||
-              (r == CUBEB_ERROR && layout == CUBEB_LAYOUT_UNDEFINED));
-
   cubeb_stream_params params = {
     CUBEB_SAMPLE_FLOAT32NE,
     preferred_rate,
     max_channels,
-    (r == CUBEB_OK) ? layout : CUBEB_LAYOUT_UNDEFINED
+    CUBEB_LAYOUT_UNDEFINED
 #if defined(__ANDROID__)
     , CUBEB_STREAM_TYPE_MUSIC
 #endif
   };
   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_mixer.cpp
+++ b/media/libcubeb/gtest/test_mixer.cpp
@@ -83,16 +83,17 @@ audio_input audio_inputs[CUBEB_LAYOUT_MA
   { CUBEB_LAYOUT_2F2,           { L, R, LS, RS } },
   { CUBEB_LAYOUT_2F2_LFE,       { L, R, LFE, LS, RS } },
   { CUBEB_LAYOUT_3F2,           { L, R, C, LS, RS } },
   { CUBEB_LAYOUT_3F2_LFE,       { L, R, C, LFE, LS, RS } },
   { CUBEB_LAYOUT_3F3R_LFE,      { L, R, C, LFE, RC, LS, RS } },
   { CUBEB_LAYOUT_3F4_LFE,       { L, R, C, LFE, RLS, RRS, LS, RS } }
 };
 
+// The test cases must be aligned with cubeb_downmix.
 void
 downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
 {
   if (in_layout == CUBEB_LAYOUT_UNDEFINED) {
     return; // Only possible output layout would be UNDEFINED.
   }
 
   cubeb_stream_params in_params = {
@@ -121,29 +122,36 @@ downmix_test(float const * data, cubeb_c
   if (!cubeb_should_downmix(&in_params, &out_params)) {
     return;
   }
 
   fprintf(stderr, "Downmix from %s to %s\n", layout_infos[in_layout].name, layout_infos[out_layout].name);
 
   unsigned int const inframes = 10;
   vector<float> in(in_params.channels * inframes);
+#if defined(__APPLE__)
+  // The mixed buffer size doesn't be changed based on the channel layout set on OSX.
+  // Please see the comment above downmix_3f2 in cubeb_mixer.cpp.
+  vector<float> out(in_params.channels * inframes);
+#else
+  // In normal case, the mixed buffer size is based on the mixing channel layout.
   vector<float> out(out_params.channels * inframes);
+#endif
 
   for (unsigned int offset = 0 ; offset < inframes * in_params.channels ; offset += in_params.channels) {
     for (unsigned int i = 0 ; i < in_params.channels ; ++i) {
       in[offset + i] = data[i];
     }
   }
 
   // Create a mixer for downmix only.
   std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)>
     mixer(cubeb_mixer_create(in_params.format, CUBEB_MIXER_DIRECTION_DOWNMIX), cubeb_mixer_destroy);
 
-  cubeb_mixer_mix(mixer.get(), in.data(), inframes, out.data(), &in_params, &out_params);
+  cubeb_mixer_mix(mixer.get(), inframes, in.data(), in.size(), out.data(), out.size(), &in_params, &out_params);
 
   uint32_t in_layout_mask = 0;
   for (unsigned int i = 0 ; i < in_params.channels; ++i) {
     in_layout_mask |= 1 << CHANNEL_INDEX_TO_ORDER[in_layout][i];
   }
 
   uint32_t out_layout_mask = 0;
   for (unsigned int i = 0 ; out_layout != CUBEB_LAYOUT_UNDEFINED && i < out_params.channels; ++i) {
@@ -152,32 +160,37 @@ downmix_test(float const * data, cubeb_c
 
   for (unsigned int i = 0 ; i < inframes * out_params.channels ; ++i) {
     unsigned int index = i % out_params.channels;
 
     // downmix_3f2
     if ((in_layout == CUBEB_LAYOUT_3F2 || in_layout == CUBEB_LAYOUT_3F2_LFE) &&
         out_layout >= CUBEB_LAYOUT_MONO && out_layout <= CUBEB_LAYOUT_2F2_LFE) {
       auto & downmix_results = DOWNMIX_3F2_RESULTS[in_layout - CUBEB_LAYOUT_3F2][out_layout - CUBEB_LAYOUT_MONO];
-      fprintf(stderr, "[3f2] Expect: %lf, Get: %lf\n", downmix_results[index], out[index]);
-      ASSERT_EQ(downmix_results[index], out[index]);
+      fprintf(stderr, "[3f2] Expect: %lf, Get: %lf\n", downmix_results[index], out[i]);
+      ASSERT_EQ(downmix_results[index], out[i]);
       continue;
     }
 
+#if defined(__APPLE__)
+    // We only support downmix for audio 5.1 on OS X currently.
+    return;
+#endif
+
     // mix_remap
     if (out_layout_mask & in_layout_mask) {
       uint32_t mask = 1 << CHANNEL_INDEX_TO_ORDER[out_layout][index];
-      fprintf(stderr, "[map channels] Expect: %lf, Get: %lf\n", (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[index]);
-      ASSERT_EQ((mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[index]);
+      fprintf(stderr, "[map channels] Expect: %lf, Get: %lf\n", (mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
+      ASSERT_EQ((mask & in_layout_mask) ? audio_inputs[out_layout].data[index] : 0, out[i]);
       continue;
     }
 
     // downmix_fallback
-    fprintf(stderr, "[fallback] Expect: %lf, Get: %lf\n", audio_inputs[in_layout].data[index], out[index]);
-    ASSERT_EQ(audio_inputs[in_layout].data[index], out[index]);
+    fprintf(stderr, "[fallback] Expect: %lf, Get: %lf\n", audio_inputs[in_layout].data[index], out[i]);
+    ASSERT_EQ(audio_inputs[in_layout].data[index], out[i]);
   }
 }
 
 TEST(cubeb, mixer)
 {
   for (auto audio_input : audio_inputs) {
     for (auto audio_output : layout_infos) {
       downmix_test(audio_input.data, audio_input.layout, audio_output.layout);
--- a/media/libcubeb/gtest/test_overload_callback.cpp
+++ b/media/libcubeb/gtest/test_overload_callback.cpp
@@ -53,17 +53,17 @@ void state_cb(cubeb_stream * stream, voi
 TEST(cubeb, overload_callback)
 {
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params output_params;
   int r;
   uint32_t latency_frames = 0;
 
-  r = cubeb_init(&ctx, "Cubeb callback overload", NULL);
+  r = common_init(&ctx, "Cubeb callback overload");
   ASSERT_EQ(r, CUBEB_OK);
 
   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;
--- a/media/libcubeb/gtest/test_record.cpp
+++ b/media/libcubeb/gtest/test_record.cpp
@@ -72,17 +72,17 @@ TEST(cubeb, record)
     fprintf(stderr, "Set log callback failed\n");
   }
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
   int r;
   user_state_record stream_state = { false };
 
-  r = cubeb_init(&ctx, "Cubeb record example", NULL);
+  r = common_init(&ctx, "Cubeb record example");
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   /* This test needs an available input device, skip it if this host does not
    * have one. */
   if (!has_available_input_device(ctx)) {
--- a/media/libcubeb/gtest/test_sanity.cpp
+++ b/media/libcubeb/gtest/test_sanity.cpp
@@ -72,17 +72,17 @@ test_state_callback(cubeb_stream * /*stm
 }
 
 TEST(cubeb, init_destroy_context)
 {
   int r;
   cubeb * ctx;
   char const* backend_id;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  r = common_init(&ctx, "test_sanity");
   ASSERT_EQ(r, CUBEB_OK);
   ASSERT_NE(ctx, nullptr);
 
   backend_id = cubeb_get_backend_id(ctx);
   ASSERT_TRUE(backend_id);
 
   fprintf(stderr, "Backend: %s\n", backend_id);
 
@@ -93,35 +93,36 @@ TEST(cubeb, init_destroy_multiple_contex
 {
   size_t i;
   int r;
   cubeb * ctx[4];
   int order[4] = {2, 0, 3, 1};
   ASSERT_EQ(ARRAY_LENGTH(ctx), ARRAY_LENGTH(order));
 
   for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
-    r = cubeb_init(&ctx[i], NULL, NULL);
+    r = common_init(&ctx[i], NULL);
     ASSERT_EQ(r, CUBEB_OK);
     ASSERT_NE(ctx[i], nullptr);
   }
 
   /* destroy in a different order */
   for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
     cubeb_destroy(ctx[order[i]]);
   }
 }
 
 TEST(cubeb, context_variables)
 {
   int r;
   cubeb * ctx;
   uint32_t value;
+  cubeb_channel_layout layout;
   cubeb_stream_params params;
 
-  r = cubeb_init(&ctx, "test_context_variables", NULL);
+  r = common_init(&ctx, "test_context_variables");
   ASSERT_EQ(r, CUBEB_OK);
   ASSERT_NE(ctx, nullptr);
 
   params.channels = STREAM_CHANNELS;
   params.format = STREAM_FORMAT;
   params.rate = STREAM_RATE;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -134,27 +135,32 @@ TEST(cubeb, context_variables)
   }
 
   r = cubeb_get_preferred_sample_rate(ctx, &value);
   ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
   if (r == CUBEB_OK) {
     ASSERT_TRUE(value > 0);
   }
 
+  r = cubeb_get_preferred_channel_layout(ctx, &layout);
+  ASSERT_TRUE(r == CUBEB_ERROR_NOT_SUPPORTED ||
+              (r == CUBEB_OK && layout != CUBEB_LAYOUT_UNDEFINED) ||
+              (r == CUBEB_ERROR && layout == CUBEB_LAYOUT_UNDEFINED));
+
   cubeb_destroy(ctx);
 }
 
 TEST(cubeb, init_destroy_stream)
 {
   int r;
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params params;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -173,17 +179,17 @@ TEST(cubeb, init_destroy_stream)
 TEST(cubeb, init_destroy_multiple_streams)
 {
   size_t i;
   int r;
   cubeb * ctx;
   cubeb_stream * stream[8];
   cubeb_stream_params params;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -206,17 +212,17 @@ TEST(cubeb, init_destroy_multiple_stream
 
 TEST(cubeb, configure_stream)
 {
   int r;
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params params;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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_STEREO;
 #if defined(__ANDROID__)
@@ -242,17 +248,17 @@ 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;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -342,17 +348,17 @@ TEST(cubeb, init_destroy_multiple_contex
   params.rate = STREAM_RATE;
   params.channels = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
   params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
 #endif
 
   for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
-    r = cubeb_init(&ctx[i], "test_sanity", NULL);
+    r = common_init(&ctx[i], "test_sanity");
     ASSERT_EQ(r, CUBEB_OK);
     ASSERT_NE(ctx[i], nullptr);
 
     for (j = 0; j < streams_per_ctx; ++j) {
       r = cubeb_stream_init(ctx[i], &stream[i * streams_per_ctx + j], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
                             test_data_callback, test_state_callback, &dummy);
       ASSERT_EQ(r, CUBEB_OK);
       ASSERT_NE(stream[i * streams_per_ctx + j], nullptr);
@@ -370,17 +376,17 @@ TEST(cubeb, init_destroy_multiple_contex
 TEST(cubeb, basic_stream_operations)
 {
   int r;
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params params;
   uint64_t position;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -421,17 +427,17 @@ TEST(cubeb, stream_position)
   int r;
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params params;
   uint64_t position, last_position;
 
   total_frames_written = 0;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
@@ -557,17 +563,17 @@ TEST(cubeb, drain)
   cubeb * ctx;
   cubeb_stream * stream;
   cubeb_stream_params params;
   uint64_t position;
 
   delay_callback = 0;
   total_frames_written = 0;
 
-  r = cubeb_init(&ctx, "test_sanity", NULL);
+  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 = STREAM_CHANNELS;
   params.layout = STREAM_LAYOUT;
 #if defined(__ANDROID__)
--- a/media/libcubeb/gtest/test_tone.cpp
+++ b/media/libcubeb/gtest/test_tone.cpp
@@ -79,17 +79,17 @@ void state_cb_tone(cubeb_stream *stream,
 
 TEST(cubeb, tone)
 {
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
   int r;
 
-  r = cubeb_init(&ctx, "Cubeb tone example", NULL);
+  r = common_init(&ctx, "Cubeb tone example");
   ASSERT_EQ(r, CUBEB_OK) << "Error initializing cubeb library";
 
   std::unique_ptr<cubeb, decltype(&cubeb_destroy)>
     cleanup_cubeb_at_exit(ctx, cubeb_destroy);
 
   params.format = STREAM_FORMAT;
   params.rate = SAMPLE_FREQUENCY;
   params.channels = 1;
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -3,16 +3,17 @@
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #if !defined(CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382)
 #define CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382
 
 #include <stdint.h>
+#include <stdlib.h>
 #include "cubeb_export.h"
 
 #if defined(__cplusplus)
 extern "C" {
 #endif
 
 /** @mainpage
 
@@ -347,26 +348,26 @@ typedef struct {
 
   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. */
 
-  unsigned int latency_lo; /**< Lowest possible latency in frames. */
-  unsigned int latency_hi; /**< Higest possible latency in frames. */
+  unsigned int latency_lo;    /**< Lowest possible latency in frames. */
+  unsigned int 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 {
-  uint32_t count;                 /**< Device count in collection. */
-  cubeb_device_info * device[1];  /**< Array of pointers to device info. */
+  cubeb_device_info * device; /**< Array of pointers to device info. */
+  size_t count;               /**< Device count in collection. */
 } cubeb_device_collection;
 
 /** User supplied data callback.
     - Calling other cubeb functions from this callback is unsafe.
     - The code in the callback should be non-blocking.
     - Returning less than the number of frames this callback asks for or
       provides puts the stream in drain mode. This callback will not be called
       again, and the state callback will be called with CUBEB_STATE_DRAINED when
@@ -607,17 +608,17 @@ CUBEB_EXPORT int cubeb_stream_register_d
     @param context
     @param devtype device type to include
     @param collection output collection. Must be destroyed with cubeb_device_collection_destroy
     @retval CUBEB_OK in case of success
     @retval CUBEB_ERROR_INVALID_PARAMETER if collection is an invalid pointer
     @retval CUBEB_ERROR_NOT_SUPPORTED */
 CUBEB_EXPORT int cubeb_enumerate_devices(cubeb * context,
                                          cubeb_device_type devtype,
-                                         cubeb_device_collection ** collection);
+                                         cubeb_device_collection * collection);
 
 /** Destroy a cubeb_device_collection, and its `cubeb_device_info`.
     @param context
     @param collection collection to destroy
     @retval CUBEB_OK
     @retval CUBEB_ERROR_INVALID_PARAMETER if collection is an invalid pointer */
 CUBEB_EXPORT int cubeb_device_collection_destroy(cubeb * context,
                                                  cubeb_device_collection * collection);
--- a/media/libcubeb/src/cubeb-internal.h
+++ b/media/libcubeb/src/cubeb-internal.h
@@ -46,18 +46,19 @@ struct cubeb_ops {
   char const * (* get_backend_id)(cubeb * context);
   int (* get_max_channel_count)(cubeb * context, uint32_t * max_channels);
   int (* get_min_latency)(cubeb * context,
                           cubeb_stream_params params,
                           uint32_t * latency_ms);
   int (* get_preferred_sample_rate)(cubeb * context, uint32_t * rate);
   int (* get_preferred_channel_layout)(cubeb * context, cubeb_channel_layout * layout);
   int (* enumerate_devices)(cubeb * context, cubeb_device_type type,
-                            cubeb_device_collection ** collection);
-  int (* device_collection_destroy)(cubeb * context, cubeb_device_collection * collection);
+                            cubeb_device_collection * collection);
+  int (* device_collection_destroy)(cubeb * context,
+                                    cubeb_device_collection * collection);
   void (* destroy)(cubeb * context);
   int (* 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,
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -545,47 +545,58 @@ void log_device(cubeb_device_info * devi
       device_info->max_channels,
       (devfmts[0] == '\0') ? devfmts : devfmts + 1, (unsigned int)device_info->format, devdeffmt,
       device_info->min_rate, device_info->max_rate, device_info->default_rate,
       device_info->latency_lo, device_info->latency_hi);
 }
 
 int cubeb_enumerate_devices(cubeb * context,
                             cubeb_device_type devtype,
-                            cubeb_device_collection ** collection)
+                            cubeb_device_collection * collection)
 {
   int rv;
   if ((devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) == 0)
     return CUBEB_ERROR_INVALID_PARAMETER;
   if (collection == NULL)
     return CUBEB_ERROR_INVALID_PARAMETER;
   if (!context->ops->enumerate_devices)
     return CUBEB_ERROR_NOT_SUPPORTED;
 
   rv = context->ops->enumerate_devices(context, devtype, collection);
 
   if (g_cubeb_log_callback) {
-    for (uint32_t i = 0; i < (*collection)->count; i++) {
-      log_device((*collection)->device[i]);
+    for (size_t i = 0; i < collection->count; i++) {
+      log_device(&collection->device[i]);
     }
   }
 
   return rv;
 }
 
 int cubeb_device_collection_destroy(cubeb * context,
                                     cubeb_device_collection * collection)
 {
+  int r;
+
   if (context == NULL || collection == NULL)
     return CUBEB_ERROR_INVALID_PARAMETER;
 
   if (!context->ops->device_collection_destroy)
     return CUBEB_ERROR_NOT_SUPPORTED;
 
-  return context->ops->device_collection_destroy(context, collection);
+  if (!collection->device)
+    return CUBEB_OK;
+
+  r = context->ops->device_collection_destroy(context, collection);
+  if (r == CUBEB_OK) {
+    collection->device = NULL;
+    collection->count = 0;
+  }
+
+  return r;
 }
 
 int cubeb_register_device_collection_changed(cubeb * context,
                                              cubeb_device_type devtype,
                                              cubeb_device_collection_changed_callback callback,
                                              void * user_ptr)
 {
   if (context == NULL || (devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) == 0)
--- a/media/libcubeb/src/cubeb_alsa.c
+++ b/media/libcubeb/src/cubeb_alsa.c
@@ -1283,72 +1283,84 @@ alsa_stream_set_volume(cubeb_stream * st
   stm->volume = volume;
   pthread_mutex_unlock(&stm->mutex);
 
   return CUBEB_OK;
 }
 
 static int
 alsa_enumerate_devices(cubeb * context, cubeb_device_type type,
-                       cubeb_device_collection ** collection)
+                       cubeb_device_collection * collection)
 {
+  cubeb_device_info* device = NULL;
+
   if (!context)
     return CUBEB_ERROR;
 
   uint32_t rate, max_channels;
   int r;
 
   r = alsa_get_preferred_sample_rate(context, &rate);
   if (r != CUBEB_OK) {
     return CUBEB_ERROR;
   }
 
   r = alsa_get_max_channel_count(context, &max_channels);
   if (r != CUBEB_OK) {
     return CUBEB_ERROR;
   }
 
-  *collection = (cubeb_device_collection *) calloc(1, sizeof(cubeb_device_collection) + 1*sizeof(cubeb_device_info *));
-  assert(*collection);
-
   char const * a_name = "default";
-  (*collection)->device[0] = (cubeb_device_info *) calloc(1, sizeof(cubeb_device_info));
-  assert((*collection)->device[0]);
+  device = (cubeb_device_info *) calloc(1, sizeof(cubeb_device_info));
+  assert(device);
+  if (!device)
+    return CUBEB_ERROR;
 
-  (*collection)->device[0]->device_id = strdup(a_name);
-  (*collection)->device[0]->devid = (*collection)->device[0]->device_id;
-  (*collection)->device[0]->friendly_name = strdup(a_name);
-  (*collection)->device[0]->group_id = strdup(a_name);
-  (*collection)->device[0]->vendor_name = strdup(a_name);
-  (*collection)->device[0]->type = type;
-  (*collection)->device[0]->state = CUBEB_DEVICE_STATE_ENABLED;
-  (*collection)->device[0]->preferred = CUBEB_DEVICE_PREF_ALL;
-  (*collection)->device[0]->format = CUBEB_DEVICE_FMT_S16NE;
-  (*collection)->device[0]->default_format = CUBEB_DEVICE_FMT_S16NE;
-  (*collection)->device[0]->max_channels = max_channels;
-  (*collection)->device[0]->min_rate = rate;
-  (*collection)->device[0]->max_rate = rate;
-  (*collection)->device[0]->default_rate = rate;
-  (*collection)->device[0]->latency_lo = 0;
-  (*collection)->device[0]->latency_hi = 0;
+  device->device_id = a_name;
+  device->devid = (cubeb_devid) device->device_id;
+  device->friendly_name = a_name;
+  device->group_id = a_name;
+  device->vendor_name = a_name;
+  device->type = type;
+  device->state = CUBEB_DEVICE_STATE_ENABLED;
+  device->preferred = CUBEB_DEVICE_PREF_ALL;
+  device->format = CUBEB_DEVICE_FMT_S16NE;
+  device->default_format = CUBEB_DEVICE_FMT_S16NE;
+  device->max_channels = max_channels;
+  device->min_rate = rate;
+  device->max_rate = rate;
+  device->default_rate = rate;
+  device->latency_lo = 0;
+  device->latency_hi = 0;
 
-  (*collection)->count = 1;
+  collection->device = device;
+  collection->count = 1;
+
+  return CUBEB_OK;
+}
 
+static int
+alsa_device_collection_destroy(cubeb * context,
+                               cubeb_device_collection * collection)
+{
+  assert(collection->count == 1);
+  (void) context;
+  free(collection->device);
   return CUBEB_OK;
 }
 
 static struct cubeb_ops const alsa_ops = {
   .init = alsa_init,
   .get_backend_id = alsa_get_backend_id,
   .get_max_channel_count = alsa_get_max_channel_count,
   .get_min_latency = alsa_get_min_latency,
   .get_preferred_sample_rate = alsa_get_preferred_sample_rate,
   .get_preferred_channel_layout = NULL,
   .enumerate_devices = alsa_enumerate_devices,
-  .device_collection_destroy = cubeb_utils_default_device_collection_destroy,
+  .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_get_position = alsa_stream_get_position,
   .stream_get_latency = alsa_stream_get_latency,
   .stream_set_volume = alsa_stream_set_volume,
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -24,17 +24,16 @@
 #include "cubeb-internal.h"
 #include "cubeb_mixer.h"
 #include "cubeb_panner.h"
 #if !TARGET_OS_IPHONE
 #include "cubeb_osx_run_loop.h"
 #endif
 #include "cubeb_resampler.h"
 #include "cubeb_ring_array.h"
-#include "cubeb_utils.h"
 #include <algorithm>
 #include <atomic>
 #include <vector>
 #include <sys/time.h>
 
 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
 typedef UInt32 AudioFormatFlags;
 #endif
@@ -383,29 +382,32 @@ is_extra_input_needed(cubeb_stream * stm
     * switching, we add some silence as well to compensate for the fact that
     * we're lacking some input data. */
   return stm->frames_read == 0 ||
          stm->available_input_frames.load() < minimum_resampling_input_frames(stm);
 }
 
 static void
 audiounit_mix_output_buffer(cubeb_stream * stm,
+                            long output_frames,
                             void * output_buffer,
-                            long output_frames)
+                            unsigned long output_buffer_length)
 {
   cubeb_stream_params output_mixer_params = {
     stm->output_stream_params.format,
     stm->output_stream_params.rate,
     CUBEB_CHANNEL_LAYOUT_MAPS[stm->context->layout].channels,
     stm->context->layout
   };
 
   // The downmixing(from 5.1) supports in-place conversion, so we can use
   // the same buffer for both input and output of the mixer.
-  cubeb_mixer_mix(stm->mixer.get(), output_buffer, output_frames, output_buffer,
+  cubeb_mixer_mix(stm->mixer.get(), output_frames,
+                  output_buffer, output_buffer_length,
+                  output_buffer, output_buffer_length,
                   &stm->output_stream_params, &output_mixer_params);
 }
 
 static OSStatus
 audiounit_output_callback(void * user_ptr,
                           AudioUnitRenderActionFlags * /* flags */,
                           AudioTimeStamp const * tstamp,
                           UInt32 bus,
@@ -517,17 +519,18 @@ 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 */
-  audiounit_mix_output_buffer(stm, output_buffer, output_frames);
+  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 */)
 {
@@ -2913,21 +2916,22 @@ audiounit_strref_to_cstr_utf8(CFStringRe
 {
   CFIndex len, size;
   char * ret;
   if (strref == NULL) {
     return NULL;
   }
 
   len = CFStringGetLength(strref);
-  size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
-  ret = static_cast<char *>(malloc(size));
+  // Add 1 to size to allow for '\0' termination character.
+  size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
+  ret = new char[size];
 
   if (!CFStringGetCString(strref, ret, size, kCFStringEncodingUTF8)) {
-    free(ret);
+    delete [] ret;
     ret = NULL;
   }
 
   return ret;
 }
 
 static uint32_t
 audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope)
@@ -3014,48 +3018,46 @@ audiounit_get_device_presentation_latenc
   size = sizeof(UInt32);
   if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &offset) != noErr) {
     offset = 0;
   }
 
   return dev + stream + offset;
 }
 
-static cubeb_device_info *
-audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type)
+static int
+audiounit_create_device_from_hwdev(cubeb_device_info * ret, AudioObjectID devid, cubeb_device_type type)
 {
   AudioObjectPropertyAddress adr = { 0, 0, kAudioObjectPropertyElementMaster };
   UInt32 size, ch, latency;
-  cubeb_device_info * ret;
   CFStringRef str = NULL;
   AudioValueRange range;
 
   if (type == CUBEB_DEVICE_TYPE_OUTPUT) {
     adr.mScope = kAudioDevicePropertyScopeOutput;
   } else if (type == CUBEB_DEVICE_TYPE_INPUT) {
     adr.mScope = kAudioDevicePropertyScopeInput;
   } else {
-    return NULL;
+    return CUBEB_ERROR;
   }
 
   ch = audiounit_get_channel_count(devid, adr.mScope);
   if (ch == 0) {
-    return NULL;
+    return CUBEB_ERROR;
   }
 
-  ret = new cubeb_device_info;
   PodZero(ret, 1);
 
   size = sizeof(CFStringRef);
   adr.mSelector = kAudioDevicePropertyDeviceUID;
   if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &str) == noErr && str != NULL) {
     ret->device_id = audiounit_strref_to_cstr_utf8(str);
     static_assert(sizeof(cubeb_devid) >= sizeof(decltype(devid)), "cubeb_devid can't represent devid");
     ret->devid = reinterpret_cast<cubeb_devid>(devid);
-    ret->group_id = strdup(ret->device_id);
+    ret->group_id = ret->device_id;
     CFRelease(str);
   }
 
   size = sizeof(CFStringRef);
   adr.mSelector = kAudioObjectPropertyName;
   if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &str) == noErr && str != NULL) {
     UInt32 ds;
     size = sizeof(UInt32);
@@ -3103,52 +3105,78 @@ audiounit_create_device_from_hwdev(Audio
   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_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
   }
 
-  return ret;
+  return CUBEB_OK;
 }
 
 static int
 audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
-                            cubeb_device_collection ** collection)
+                            cubeb_device_collection * collection)
 {
   std::vector<AudioObjectID> hwdevs;
   uint32_t i;
   OSStatus err;
 
   err = audiounit_get_devices(hwdevs);
   if (err != noErr) {
     return CUBEB_ERROR;
   }
 
-  *collection = static_cast<cubeb_device_collection *>(malloc(sizeof(cubeb_device_collection) +
-							      sizeof(cubeb_device_info*) * (hwdevs.size() > 0 ? hwdevs.size() - 1 : 0)));
-  (*collection)->count = 0;
+  auto devices = new cubeb_device_info[hwdevs.size()];
+  collection->count = 0;
 
   if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
     for (i = 0; i < hwdevs.size(); i++) {
-      cubeb_device_info * cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_OUTPUT);
-      if (cur != nullptr)
-	(*collection)->device[(*collection)->count++] = cur;
+      auto device = &devices[collection->count];
+      auto err = audiounit_create_device_from_hwdev(device, hwdevs[i], CUBEB_DEVICE_TYPE_OUTPUT);
+      if (err != CUBEB_OK) {
+        continue;
+      }
+      collection->count += 1;
     }
   }
 
   if (type & CUBEB_DEVICE_TYPE_INPUT) {
     for (i = 0; i < hwdevs.size(); i++) {
-      cubeb_device_info * cur = audiounit_create_device_from_hwdev(hwdevs[i], CUBEB_DEVICE_TYPE_INPUT);
-      if (cur != nullptr)
-	(*collection)->device[(*collection)->count++] = cur;
+      auto device = &devices[collection->count];
+      auto err = audiounit_create_device_from_hwdev(device, hwdevs[i], CUBEB_DEVICE_TYPE_INPUT);
+      if (err != CUBEB_OK) {
+        continue;
+      }
+      collection->count += 1;
     }
   }
 
+  if (collection->count > 0) {
+    collection->device = devices;
+  } else {
+    delete [] devices;
+    collection->device = NULL;
+  }
+
+  return CUBEB_OK;
+}
+
+static int
+audiounit_device_collection_destroy(cubeb * /* context */,
+                                    cubeb_device_collection * collection)
+{
+  for (size_t i = 0; i < collection->count; i++) {
+    delete [] collection->device[i].device_id;
+    delete [] collection->device[i].friendly_name;
+    delete [] collection->device[i].vendor_name;
+  }
+  delete [] collection->device;
+
   return CUBEB_OK;
 }
 
 static std::vector<AudioObjectID>
 audiounit_get_devices_of_type(cubeb_device_type devtype)
 {
   AudioObjectPropertyAddress adr = { kAudioHardwarePropertyDevices,
                                      kAudioObjectPropertyScopeGlobal,
@@ -3300,17 +3328,17 @@ int audiounit_register_device_collection
 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,
-  /*.device_collection_destroy =*/ cubeb_utils_default_device_collection_destroy,
+  /*.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_get_position =*/ audiounit_stream_get_position,
   /*.stream_get_latency =*/ audiounit_stream_get_latency,
   /*.stream_set_volume =*/ audiounit_stream_set_volume,
--- a/media/libcubeb/src/cubeb_jack.cpp
+++ b/media/libcubeb/src/cubeb_jack.cpp
@@ -88,17 +88,17 @@ static int cbjack_get_preferred_sample_r
 static void cbjack_destroy(cubeb * context);
 static void cbjack_interleave_capture(cubeb_stream * stream, float **in, jack_nframes_t nframes, bool format_mismatch);
 static void cbjack_deinterleave_playback_refill_s16ne(cubeb_stream * stream, short **bufs_in, float **bufs_out, jack_nframes_t nframes);
 static void cbjack_deinterleave_playback_refill_float(cubeb_stream * stream, float **bufs_in, float **bufs_out, jack_nframes_t nframes);
 static int cbjack_stream_device_destroy(cubeb_stream * stream,
                                         cubeb_device * device);
 static int cbjack_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const device);
 static int cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
-                                    cubeb_device_collection ** collection);
+                                    cubeb_device_collection * collection);
 static int cbjack_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,
                               cubeb_data_callback data_callback,
                               cubeb_state_callback state_callback,
@@ -175,17 +175,16 @@ struct cubeb {
   float in_resampled_interleaved_buffer_float[FIFO_SIZE * MAX_CHANNELS * 3];
   int16_t in_resampled_interleaved_buffer_s16ne[FIFO_SIZE * MAX_CHANNELS * 3];
   float out_resampled_interleaved_buffer_float[FIFO_SIZE * MAX_CHANNELS * 3];
   int16_t out_resampled_interleaved_buffer_s16ne[FIFO_SIZE * MAX_CHANNELS * 3];
 
   cubeb_stream streams[MAX_STREAMS];
   unsigned int active_streams;
 
-  cubeb_device_info * devinfo[2];
   cubeb_device_collection_changed_callback collection_changed_callback;
 
   bool active;
   unsigned int jack_sample_rate;
   unsigned int jack_latency;
   unsigned int jack_xruns;
   unsigned int jack_buffer_size;
   unsigned int fragment_size;
@@ -969,73 +968,68 @@ cbjack_stream_device_destroy(cubeb_strea
   if (device->output_name)
     free(device->output_name);
   free(device);
   return CUBEB_OK;
 }
 
 static int
 cbjack_enumerate_devices(cubeb * context, cubeb_device_type type,
-                         cubeb_device_collection ** collection)
+                         cubeb_device_collection * collection)
 {
   if (!context)
     return CUBEB_ERROR;
 
   uint32_t rate;
-  uint8_t i = 0;
-  uint8_t j;
   cbjack_get_preferred_sample_rate(context, &rate);
   const char * j_in = "JACK capture";
   const char * j_out = "JACK playback";
 
+  cubeb_device_info * devices = new cubeb_device_info[2];
+    reinterpret_cast<cubeb_device_info *>(calloc(2, sizeof(cubeb_device_info)));
+  collection->count = 0;
+
   if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
-    context->devinfo[i] = (cubeb_device_info *) malloc(sizeof(cubeb_device_info));
-    context->devinfo[i]->device_id = strdup(j_out);
-    context->devinfo[i]->devid = (cubeb_devid) context->devinfo[i]->device_id;
-    context->devinfo[i]->friendly_name = strdup(j_out);
-    context->devinfo[i]->group_id = strdup(j_out);
-    context->devinfo[i]->vendor_name = strdup(j_out);
-    context->devinfo[i]->type = CUBEB_DEVICE_TYPE_OUTPUT;
-    context->devinfo[i]->state = CUBEB_DEVICE_STATE_ENABLED;
-    context->devinfo[i]->preferred = CUBEB_DEVICE_PREF_ALL;
-    context->devinfo[i]->format = CUBEB_DEVICE_FMT_F32NE;
-    context->devinfo[i]->default_format = CUBEB_DEVICE_FMT_F32NE;
-    context->devinfo[i]->max_channels = MAX_CHANNELS;
-    context->devinfo[i]->min_rate = rate;
-    context->devinfo[i]->max_rate = rate;
-    context->devinfo[i]->default_rate = rate;
-    context->devinfo[i]->latency_lo = 0;
-    context->devinfo[i]->latency_hi = 0;
-    i++;
+    cubeb_device_info * cur = &devices[collection->count];
+    cur->device_id = strdup(j_out);
+    cur->devid = (cubeb_devid) cur->device_id;
+    cur->friendly_name = strdup(j_out);
+    cur->group_id = strdup(j_out);
+    cur->vendor_name = strdup(j_out);
+    cur->type = CUBEB_DEVICE_TYPE_OUTPUT;
+    cur->state = CUBEB_DEVICE_STATE_ENABLED;
+    cur->preferred = CUBEB_DEVICE_PREF_ALL;
+    cur->format = CUBEB_DEVICE_FMT_F32NE;
+    cur->default_format = CUBEB_DEVICE_FMT_F32NE;
+    cur->max_channels = MAX_CHANNELS;
+    cur->min_rate = rate;
+    cur->max_rate = rate;
+    cur->default_rate = rate;
+    cur->latency_lo = 0;
+    cur->latency_hi = 0;
+    collection->count +=1 ;
   }
 
   if (type & CUBEB_DEVICE_TYPE_INPUT) {
-    context->devinfo[i] = (cubeb_device_info *) malloc(sizeof(cubeb_device_info));
-    context->devinfo[i]->device_id = strdup(j_in);
-    context->devinfo[i]->devid = (cubeb_devid) context->devinfo[i]->device_id;
-    context->devinfo[i]->friendly_name = strdup(j_in);
-    context->devinfo[i]->group_id = strdup(j_in);
-    context->devinfo[i]->vendor_name = strdup(j_in);
-    context->devinfo[i]->type = CUBEB_DEVICE_TYPE_INPUT;
-    context->devinfo[i]->state = CUBEB_DEVICE_STATE_ENABLED;
-    context->devinfo[i]->preferred = CUBEB_DEVICE_PREF_ALL;
-    context->devinfo[i]->format = CUBEB_DEVICE_FMT_F32NE;
-    context->devinfo[i]->default_format = CUBEB_DEVICE_FMT_F32NE;
-    context->devinfo[i]->max_channels = MAX_CHANNELS;
-    context->devinfo[i]->min_rate = rate;
-    context->devinfo[i]->max_rate = rate;
-    context->devinfo[i]->default_rate = rate;
-    context->devinfo[i]->latency_lo = 0;
-    context->devinfo[i]->latency_hi = 0;
-    i++;
+    cubeb_device_info * cur = &devices[collection->count];
+    cur->device_id = strdup(j_in);
+    cur->devid = (cubeb_devid) cur->device_id;
+    cur->friendly_name = strdup(j_in);
+    cur->group_id = strdup(j_in);
+    cur->vendor_name = strdup(j_in);
+    cur->type = CUBEB_DEVICE_TYPE_INPUT;
+    cur->state = CUBEB_DEVICE_STATE_ENABLED;
+    cur->preferred = CUBEB_DEVICE_PREF_ALL;
+    cur->format = CUBEB_DEVICE_FMT_F32NE;
+    cur->default_format = CUBEB_DEVICE_FMT_F32NE;
+    cur->max_channels = MAX_CHANNELS;
+    cur->min_rate = rate;
+    cur->max_rate = rate;
+    cur->default_rate = rate;
+    cur->latency_lo = 0;
+    cur->latency_hi = 0;
+    collection->count += 1;
   }
 
-  *collection = (cubeb_device_collection *)
-                 malloc(sizeof(cubeb_device_collection) +
-                        i * sizeof(cubeb_device_info *));
+  collection->device = devices;
 
-  (*collection)->count = i;
-
-  for (j = 0; j < i; j++) {
-    (*collection)->device[j] = context->devinfo[j];
-  }
   return CUBEB_OK;
 }
--- a/media/libcubeb/src/cubeb_mixer.cpp
+++ b/media/libcubeb/src/cubeb_mixer.cpp
@@ -244,17 +244,20 @@ static float const DOWNMIX_MATRIX_3F2_LF
 // Fig. 3:
 // |<---------- 1 ---------->|<---------- 2 ---------->|
 // +----+----+---+---+---+---+----+----+---+---+---+---+
 // | L0 | R0 | x | x | x | x | L1 | R1 | x | x | x | x | ...
 // +----+----+---+---+---+---+----+----+---+---+---+---+
 //           |<--  dummy  -->|         |<--  dummy  -->|
 template<typename T>
 bool
-downmix_3f2(T const * const in, unsigned long inframes, T * out, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
+downmix_3f2(unsigned 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)
 {
   if ((in_layout != CUBEB_LAYOUT_3F2 && in_layout != CUBEB_LAYOUT_3F2_LFE) ||
       out_layout < CUBEB_LAYOUT_MONO || out_layout > CUBEB_LAYOUT_2F2_LFE) {
     return false;
   }
 
   unsigned int in_channels = CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels;
   unsigned int out_channels = CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels;
@@ -266,35 +269,41 @@ downmix_3f2(T const * const in, unsigned
   unsigned long out_index = 0;
   for (unsigned long i = 0 ; i < inframes * in_channels; i += in_channels) {
     for (unsigned int j = 0; j < out_channels; ++j) {
       T sample = 0;
       for (unsigned int k = 0 ; k < INPUT_CHANNEL_NUM ; ++k) {
         // 3F2-LFE has 6 channels: L, R, C, LFE, LS, RS, while 3F2 has only 5
         // channels: L, R, C, LS, RS. Thus, we need to append 0 to LFE(index 3)
         // to simulate a 3F2-LFE data when input layout is 3F2.
+        assert((in_layout == CUBEB_LAYOUT_3F2_LFE || k < 3) ? (i + k < in_len) : (k == 3) ? true : (i + k - 1 < in_len));
         T data = (in_layout == CUBEB_LAYOUT_3F2_LFE) ? in[i + k] : (k == 3) ? 0 : in[i + ((k < 3) ? k : k - 1)];
         sample += downmix_matrix[j][k] * data;
       }
+      assert(out_index + j < out_len);
       out[out_index + j] = sample;
     }
 #if defined(USE_AUDIOUNIT)
     out_index += in_channels;
 #else
     out_index += out_channels;
 #endif
   }
 
   return true;
 }
 
 /* Map the audio data by channel name. */
 template<class T>
 bool
-mix_remap(T const * const in, unsigned long inframes, T * out, cubeb_channel_layout in_layout, cubeb_channel_layout out_layout) {
+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);
 
   // 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;
   }
 
@@ -316,51 +325,59 @@ mix_remap(T const * const in, unsigned l
     return false;
   }
 
   for (unsigned long i = 0, out_index = 0; i < 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(out_index + j < out_len);
       if (in_layout_mask & channel_mask) {
+        assert(i + channel_index < in_len);
         assert(channel_index != -1);
         out[out_index + j] = in[i + channel_index];
       } else {
         assert(channel_index == -1);
         out[out_index + j] = 0;
       }
     }
   }
 
   return true;
 }
 
 /* Drop the extra channels beyond the provided output channels. */
 template<typename T>
 void
-downmix_fallback(T const * const in, unsigned long inframes, T * out, unsigned int in_channels, unsigned int out_channels)
+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);
 
   if (in_channels == out_channels && in == out) {
     return;
   }
 
   for (unsigned long i = 0, out_index = 0; i < inframes * in_channels; i += in_channels, out_index += out_channels) {
     for (unsigned int j = 0; j < out_channels; ++j) {
+      assert(i + j < in_len && out_index + j < out_len);
       out[out_index + j] = in[i + j];
     }
   }
 }
 
 
 template<typename T>
 void
-cubeb_downmix(T const * const in, long inframes, T * out,
+cubeb_downmix(long inframes,
+              T const * const in, unsigned long in_len,
+              T * out, unsigned long out_len,
               cubeb_stream_params const * stream_params,
               cubeb_stream_params const * mixer_params)
 {
   assert(in && out);
   assert(inframes);
   assert(stream_params->channels >= mixer_params->channels &&
          mixer_params->channels > 0);
   assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
@@ -370,79 +387,85 @@ cubeb_downmix(T const * const in, long i
 
   unsigned int out_channels = mixer_params->channels;
   cubeb_channel_layout out_layout = mixer_params->layout;
 
   // If the channel number is different from the layout's setting,
   // then we use fallback downmix mechanism.
   if (out_channels == CUBEB_CHANNEL_LAYOUT_MAPS[out_layout].channels &&
       in_channels == CUBEB_CHANNEL_LAYOUT_MAPS[in_layout].channels) {
-    if (downmix_3f2(in, inframes, out, in_layout, out_layout)) {
+    if (downmix_3f2(inframes, in, in_len, out, out_len, in_layout, out_layout)) {
       return;
     }
 
-  // We only support downmix for audio 5.1 currently.
 #if defined(USE_AUDIOUNIT)
+  // We only support downmix for audio 5.1 on OS X currently.
   return;
 #endif
 
-    if (mix_remap(in, inframes, out, in_layout, out_layout)) {
+    if (mix_remap(inframes, in, in_len, out, out_len, in_layout, out_layout)) {
       return;
     }
   }
 
-  downmix_fallback(in, inframes, out, in_channels, out_channels);
+  downmix_fallback(inframes, in, in_len, out, out_len, in_channels, out_channels);
 }
 
 /* Upmix function, copies a mono channel into L and R. */
 template<typename T>
 void
-mono_to_stereo(T const * in, long insamples, T * out, unsigned int out_channels)
+mono_to_stereo(long insamples, T const * in, unsigned long in_len,
+               T * out, unsigned long out_len, unsigned int out_channels)
 {
   for (long i = 0, j = 0; i < insamples; ++i, j += out_channels) {
+    assert(i < in_len && j + 1 < out_len);
     out[j] = out[j + 1] = in[i];
   }
 }
 
 template<typename T>
 void
-cubeb_upmix(T const * in, long inframes, T * out,
+cubeb_upmix(long inframes,
+            T const * const in, unsigned long in_len,
+            T * out, unsigned long out_len,
             cubeb_stream_params const * stream_params,
             cubeb_stream_params const * mixer_params)
 {
   assert(in && out);
   assert(inframes);
   assert(mixer_params->channels >= stream_params->channels &&
          stream_params->channels > 0);
 
   unsigned int in_channels = stream_params->channels;
   unsigned int out_channels = mixer_params->channels;
 
   /* Either way, if we have 2 or more channels, the first two are L and R. */
   /* If we are playing a mono stream over stereo speakers, copy the data over. */
   if (in_channels == 1 && out_channels >= 2) {
-    mono_to_stereo(in, inframes, out, out_channels);
+    mono_to_stereo(inframes, in, in_len, out, out_len, out_channels);
   } else {
     /* Copy through. */
     for (unsigned int i = 0, o = 0; i < inframes * in_channels;
         i += in_channels, o += out_channels) {
       for (unsigned int j = 0; j < in_channels; ++j) {
+        assert(i + j < in_len && o + j < out_len);
         out[o + j] = in[i + j];
       }
     }
   }
 
   /* Check if more channels. */
   if (out_channels <= 2) {
     return;
   }
 
   /* Put silence in remaining channels. */
   for (long i = 0, o = 0; i < inframes; ++i, o += out_channels) {
     for (unsigned int j = 2; j < out_channels; ++j) {
+      assert(o + j < out_len);
       out[o + j] = 0.0;
     }
   }
 }
 
 bool
 cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer)
 {
@@ -466,46 +489,50 @@ cubeb_should_downmix(cubeb_stream_params
 
 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);
 }
 
 struct cubeb_mixer {
-  virtual void mix(void * input_buffer, long frames, void * output_buffer,
+  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;
   virtual ~cubeb_mixer() {};
 };
 
 template<typename T>
 struct cubeb_mixer_impl : public cubeb_mixer {
   explicit cubeb_mixer_impl(unsigned int d)
     : direction(d)
   {
   }
 
-  void mix(void * input_buffer, long frames, void * output_buffer,
+  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)
   {
     if (frames <= 0) {
       return;
     }
 
     T * in = static_cast<T*>(input_buffer);
     T * out = static_cast<T*>(output_buffer);
 
     if ((direction & CUBEB_MIXER_DIRECTION_DOWNMIX) &&
         cubeb_should_downmix(stream_params, mixer_params)) {
-      cubeb_downmix(in, frames, out, stream_params, mixer_params);
+      cubeb_downmix(frames, in, input_buffer_length, out, output_buffer_length, stream_params, mixer_params);
     } else if ((direction & CUBEB_MIXER_DIRECTION_UPMIX) &&
                cubeb_should_upmix(stream_params, mixer_params)) {
-      cubeb_upmix(in, frames, out, stream_params, mixer_params);
+      cubeb_upmix(frames, in, input_buffer_length, out, output_buffer_length, stream_params, mixer_params);
     }
   }
 
   ~cubeb_mixer_impl() {};
 
   unsigned char const direction;
 };
 
@@ -525,16 +552,18 @@ cubeb_mixer * cubeb_mixer_create(cubeb_s
   }
 }
 
 void cubeb_mixer_destroy(cubeb_mixer * mixer)
 {
   delete mixer;
 }
 
-void cubeb_mixer_mix(cubeb_mixer * mixer,
-                     void * const input_buffer, long frames, void * output_buffer,
+void cubeb_mixer_mix(cubeb_mixer * mixer, long frames,
+                     void * input_buffer, unsigned long input_buffer_length,
+                     void * output_buffer, unsigned long outputput_buffer_length,
                      cubeb_stream_params const * stream_params,
                      cubeb_stream_params const * mixer_params)
 {
   assert(mixer);
-  mixer->mix(input_buffer, frames, output_buffer, stream_params, mixer_params);
+  mixer->mix(frames, input_buffer, input_buffer_length, output_buffer, outputput_buffer_length,
+             stream_params, mixer_params);
 }
--- a/media/libcubeb/src/cubeb_mixer.h
+++ b/media/libcubeb/src/cubeb_mixer.h
@@ -72,18 +72,19 @@ typedef enum {
   CUBEB_MIXER_DIRECTION_DOWNMIX = 0x01,
   CUBEB_MIXER_DIRECTION_UPMIX   = 0x02,
 } cubeb_mixer_direction;
 
 typedef struct cubeb_mixer cubeb_mixer;
 cubeb_mixer * cubeb_mixer_create(cubeb_sample_format format,
                                  unsigned char direction);
 void cubeb_mixer_destroy(cubeb_mixer * mixer);
-void cubeb_mixer_mix(cubeb_mixer * mixer,
-                     void * input_buffer, long frames, void * output_buffer,
+void cubeb_mixer_mix(cubeb_mixer * mixer, long frames,
+                     void * input_buffer, unsigned long input_buffer_length,
+                     void * output_buffer, unsigned long outputput_buffer_length,
                      cubeb_stream_params const * stream_params,
                      cubeb_stream_params const * mixer_params);
 
 #if defined(__cplusplus)
 }
 #endif
 
 #endif // CUBEB_MIXER
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -1143,17 +1143,17 @@ pulse_stream_set_panning(cubeb_stream * 
 
   return CUBEB_OK;
 }
 
 typedef struct {
   char * default_sink_name;
   char * default_source_name;
 
-  cubeb_device_info ** devinfo;
+  cubeb_device_info * devinfo;
   uint32_t max;
   uint32_t count;
   cubeb * context;
 } pulse_dev_list_data;
 
 static cubeb_device_fmt
 pulse_format_to_cubeb_format(pa_sample_format_t format)
 {
@@ -1172,17 +1172,17 @@ pulse_format_to_cubeb_format(pa_sample_f
 }
 
 static void
 pulse_ensure_dev_list_data_list_size (pulse_dev_list_data * list_data)
 {
   if (list_data->count == list_data->max) {
     list_data->max += 8;
     list_data->devinfo = realloc(list_data->devinfo,
-        sizeof(cubeb_device_info *) * list_data->max);
+        sizeof(cubeb_device_info) * list_data->max);
   }
 }
 
 static cubeb_device_state
 pulse_get_state_from_sink_port(pa_sink_port_info * info)
 {
   if (info != NULL) {
 #if PA_CHECK_VERSION(2, 0, 0)
@@ -1204,45 +1204,46 @@ pulse_sink_info_cb(pa_context * context,
   cubeb_device_info * devinfo;
   const char * prop;
 
   (void)context;
 
   if (eol || info == NULL)
     return;
 
-  devinfo = calloc(1, sizeof(cubeb_device_info));
+  pulse_ensure_dev_list_data_list_size(list_data);
+  devinfo = &list_data->devinfo[list_data->count];
+  memset(devinfo, 0, sizeof(cubeb_device_info));
 
   devinfo->device_id = strdup(info->name);
   devinfo->devid = (cubeb_devid) devinfo->device_id;
   devinfo->friendly_name = strdup(info->description);
   prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
   if (prop)
     devinfo->group_id = strdup(prop);
   prop = WRAP(pa_proplist_gets)(info->proplist, "device.vendor.name");
   if (prop)
     devinfo->vendor_name = strdup(prop);
 
   devinfo->type = CUBEB_DEVICE_TYPE_OUTPUT;
   devinfo->state = pulse_get_state_from_sink_port(info->active_port);
   devinfo->preferred = (strcmp(info->name, list_data->default_sink_name) == 0) ?
-				 CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
+    CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
 
   devinfo->format = CUBEB_DEVICE_FMT_ALL;
   devinfo->default_format = pulse_format_to_cubeb_format(info->sample_spec.format);
   devinfo->max_channels = info->channel_map.channels;
   devinfo->min_rate = 1;
   devinfo->max_rate = PA_RATE_MAX;
   devinfo->default_rate = info->sample_spec.rate;
 
   devinfo->latency_lo = 0;
   devinfo->latency_hi = 0;
 
-  pulse_ensure_dev_list_data_list_size (list_data);
-  list_data->devinfo[list_data->count++] = devinfo;
+  list_data->count += 1;
 
   WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
 }
 
 static cubeb_device_state
 pulse_get_state_from_source_port(pa_source_port_info * info)
 {
   if (info != NULL) {
@@ -1265,46 +1266,46 @@ pulse_source_info_cb(pa_context * contex
   cubeb_device_info * devinfo;
   const char * prop;
 
   (void)context;
 
   if (eol)
     return;
 
-  devinfo = calloc(1, sizeof(cubeb_device_info));
+  pulse_ensure_dev_list_data_list_size(list_data);
+  devinfo = &list_data->devinfo[list_data->count];
+  memset(devinfo, 0, sizeof(cubeb_device_info));
 
   devinfo->device_id = strdup(info->name);
   devinfo->devid = (cubeb_devid) devinfo->device_id;
   devinfo->friendly_name = strdup(info->description);
   prop = WRAP(pa_proplist_gets)(info->proplist, "sysfs.path");
   if (prop)
     devinfo->group_id = strdup(prop);
   prop = WRAP(pa_proplist_gets)(info->proplist, "device.vendor.name");
   if (prop)
     devinfo->vendor_name = strdup(prop);
 
   devinfo->type = CUBEB_DEVICE_TYPE_INPUT;
   devinfo->state = pulse_get_state_from_source_port(info->active_port);
   devinfo->preferred = (strcmp(info->name, list_data->default_source_name) == 0) ?
-				   CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
+    CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE;
 
   devinfo->format = CUBEB_DEVICE_FMT_ALL;
   devinfo->default_format = pulse_format_to_cubeb_format(info->sample_spec.format);
   devinfo->max_channels = info->channel_map.channels;
   devinfo->min_rate = 1;
   devinfo->max_rate = PA_RATE_MAX;
   devinfo->default_rate = info->sample_spec.rate;
 
   devinfo->latency_lo = 0;
   devinfo->latency_hi = 0;
 
-  pulse_ensure_dev_list_data_list_size (list_data);
-  list_data->devinfo[list_data->count++] = devinfo;
-
+  list_data->count += 1;
   WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
 }
 
 static void
 pulse_server_info_cb(pa_context * c, const pa_server_info * i, void * userdata)
 {
   pulse_dev_list_data * list_data = userdata;
 
@@ -1315,21 +1316,20 @@ pulse_server_info_cb(pa_context * c, con
   list_data->default_sink_name = strdup(i->default_sink_name);
   list_data->default_source_name = strdup(i->default_source_name);
 
   WRAP(pa_threaded_mainloop_signal)(list_data->context->mainloop, 0);
 }
 
 static int
 pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
-                        cubeb_device_collection ** collection)
+                        cubeb_device_collection * collection)
 {
   pulse_dev_list_data user_data = { NULL, NULL, NULL, 0, 0, context };
   pa_operation * o;
-  uint32_t i;
 
   WRAP(pa_threaded_mainloop_lock)(context->mainloop);
 
   o = WRAP(pa_context_get_server_info)(context->context,
       pulse_server_info_cb, &user_data);
   if (o) {
     operation_wait(context, NULL, o);
     WRAP(pa_operation_unref)(o);
@@ -1350,25 +1350,21 @@ pulse_enumerate_devices(cubeb * context,
     if (o) {
       operation_wait(context, NULL, o);
       WRAP(pa_operation_unref)(o);
     }
   }
 
   WRAP(pa_threaded_mainloop_unlock)(context->mainloop);
 
-  *collection = malloc(sizeof(cubeb_device_collection) +
-      sizeof(cubeb_device_info *) * (user_data.count > 0 ? user_data.count - 1 : 0));
-  (*collection)->count = user_data.count;
-  for (i = 0; i < user_data.count; i++)
-    (*collection)->device[i] = user_data.devinfo[i];
+  collection->device = user_data.devinfo;
+  collection->count = user_data.count;
 
   free(user_data.default_sink_name);
   free(user_data.default_source_name);
-  free(user_data.devinfo);
   return CUBEB_OK;
 }
 
 static int
 pulse_stream_get_current_device(cubeb_stream * stm, cubeb_device ** const device)
 {
 #if PA_CHECK_VERSION(0, 9, 8)
   *device = calloc(1, sizeof(cubeb_device));
--- a/media/libcubeb/src/cubeb_sndio.c
+++ b/media/libcubeb/src/cubeb_sndio.c
@@ -24,30 +24,30 @@
 static struct cubeb_ops const sndio_ops;
 
 struct cubeb {
   struct cubeb_ops const * ops;
 };
 
 struct cubeb_stream {
   cubeb * context;
-  pthread_t th;			  /* to run real-time audio i/o */
-  pthread_mutex_t mtx;		  /* protects hdl and pos */
-  struct sio_hdl *hdl;		  /* link us to sndio */
-  int active;			  /* cubec_start() called */
-  int conv;			  /* need float->s16 conversion */
-  unsigned char *buf;		  /* data is prepared here */
-  unsigned int nfr;		  /* number of frames in buf */
-  unsigned int bpf;		  /* bytes per frame */
-  unsigned int pchan;		  /* number of play channels */
-  uint64_t rdpos;		  /* frame number Joe hears right now */
-  uint64_t wrpos;		  /* number of written frames */
+  pthread_t th;                   /* to run real-time audio i/o */
+  pthread_mutex_t mtx;            /* protects hdl and pos */
+  struct sio_hdl *hdl;            /* link us to sndio */
+  int active;                     /* cubec_start() called */
+  int conv;                       /* need float->s16 conversion */
+  unsigned char *buf;             /* data is prepared here */
+  unsigned int nfr;               /* number of frames in buf */
+  unsigned int bpf;               /* bytes per frame */
+  unsigned int pchan;             /* number of play channels */
+  uint64_t rdpos;                 /* frame number Joe hears right now */
+  uint64_t wrpos;                 /* number of written frames */
   cubeb_data_callback data_cb;    /* cb to preapare data */
   cubeb_state_callback state_cb;  /* cb to notify about state changes */
-  void *arg;			  /* user arg to {data,state}_cb */
+  void *arg;                      /* user arg to {data,state}_cb */
 };
 
 static void
 float_to_s16(void *ptr, long nsamp)
 {
   int16_t *dst = ptr;
   float *src = ptr;
   int s;
--- a/media/libcubeb/src/cubeb_utils.c
+++ b/media/libcubeb/src/cubeb_utils.c
@@ -14,27 +14,25 @@ static void
 device_info_destroy(cubeb_device_info * info)
 {
   XASSERT(info);
 
   free((void *) info->device_id);
   free((void *) info->friendly_name);
   free((void *) info->group_id);
   free((void *) info->vendor_name);
-
-  free(info);
 }
 
 int
 cubeb_utils_default_device_collection_destroy(cubeb * context,
                                               cubeb_device_collection * collection)
 {
   uint32_t i;
   XASSERT(collection);
 
   (void) context;
 
   for (i = 0; i < collection->count; i++)
-    device_info_destroy(collection->device[i]);
+    device_info_destroy(&collection->device[i]);
 
-  free(collection);
+  free(collection->device);
   return CUBEB_OK;
 }
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -553,17 +553,22 @@ refill(cubeb_stream * stm, void * input_
     stm->draining = true;
   }
 
   /* If this is not true, there will be glitches.
      It is alright to have produced less frames if we are draining, though. */
   XASSERT(out_frames == output_frames_needed || stm->draining || !has_output(stm));
 
   if (has_output(stm) && cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
-    cubeb_mixer_mix(stm->mixer.get(), dest, out_frames, output_buffer,
+    XASSERT(dest == stm->mix_buffer.data());
+    unsigned long dest_len = out_frames * stm->output_stream_params.channels;
+    XASSERT(dest_len <= stm->mix_buffer.size() / stm->bytes_per_sample);
+    unsigned long output_buffer_len = out_frames * stm->output_mix_params.channels;
+    cubeb_mixer_mix(stm->mixer.get(), out_frames,
+                    dest, dest_len, output_buffer, output_buffer_len,
                     &stm->output_stream_params, &stm->output_mix_params);
   }
 
   return out_frames;
 }
 
 /* This helper grabs all the frames available from a capture client, put them in
  * linear_input_buffer. linear_input_buffer should be cleared before the
@@ -616,21 +621,24 @@ bool get_input_buffer(cubeb_stream * stm
     if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
       LOG("insert silence: ps=%u", packet_size);
       stm->linear_input_buffer->push_silence(packet_size * stm->input_stream_params.channels);
     } else {
       if (cubeb_should_mix(&stm->input_mix_params, &stm->input_stream_params)) {
         bool ok = stm->linear_input_buffer->reserve(stm->linear_input_buffer->length() +
                                                    packet_size * stm->input_stream_params.channels);
         XASSERT(ok);
-        cubeb_mixer_mix(stm->mixer.get(), input_packet, packet_size,
-                        stm->linear_input_buffer->end(),
+        unsigned long input_packet_length = packet_size * stm->input_mix_params.channels;
+        unsigned long linear_input_buffer_length = packet_size * stm->input_stream_params.channels;
+        cubeb_mixer_mix(stm->mixer.get(), packet_size,
+                        input_packet, input_packet_length,
+                        stm->linear_input_buffer->end(), linear_input_buffer_length,
                         &stm->input_mix_params,
                         &stm->input_stream_params);
-        stm->linear_input_buffer->set_length(stm->linear_input_buffer->length() + packet_size * stm->input_stream_params.channels);
+        stm->linear_input_buffer->set_length(stm->linear_input_buffer->length() + linear_input_buffer_length);
       } else {
         stm->linear_input_buffer->push(input_packet,
                                       packet_size * stm->input_stream_params.channels);
       }
     }
     hr = stm->capture_client->ReleaseBuffer(packet_size);
     if (FAILED(hr)) {
       LOG("FAILED to release intput buffer");
@@ -718,21 +726,21 @@ refill_callback_duplex(cubeb_stream * st
   /* This can only happen when debugging, and having breakpoints set in the
    * callback in a way that it makes the stream underrun. */
   if (output_frames == 0) {
     return true;
   }
 
 
   ALOGV("Duplex callback: input frames: %Iu, output frames: %Iu",
-        stm->linear_input_buffer->length(), output_frames);
+        input_frames, output_frames);
 
   refill(stm,
          stm->linear_input_buffer->data(),
-         stm->linear_input_buffer->length(),
+         input_frames,
          output_buffer,
          output_frames);
 
   stm->linear_input_buffer->clear();
 
   hr = stm->render_client->ReleaseBuffer(output_frames, 0);
   if (FAILED(hr)) {
     LOG("failed to release buffer: %lx", hr);
@@ -740,34 +748,35 @@ refill_callback_duplex(cubeb_stream * st
   }
   return true;
 }
 
 bool
 refill_callback_input(cubeb_stream * stm)
 {
   bool rv;
+  size_t input_frames;
 
   XASSERT(has_input(stm) && !has_output(stm));
 
   rv = get_input_buffer(stm);
   if (!rv) {
     return rv;
   }
 
-  // This can happen at the very beginning of the stream.
-  if (!stm->linear_input_buffer->length()) {
+  input_frames = stm->linear_input_buffer->length() / stm->input_stream_params.channels;
+  if (!input_frames) {
     return true;
   }
 
-  ALOGV("Input callback: input frames: %Iu", stm->linear_input_buffer->length());
+  ALOGV("Input callback: input frames: %Iu", input_frames);
 
   long read = refill(stm,
                      stm->linear_input_buffer->data(),
-                     stm->linear_input_buffer->length(),
+                     input_frames,
                      nullptr,
                      0);
 
   XASSERT(read >= 0);
 
   stm->linear_input_buffer->clear();
 
   return !stm->draining;
@@ -2137,67 +2146,65 @@ wasapi_is_default_device(EDataFlow flow,
       com_heap_ptr<wchar_t> defdevid(tmp);
       ret = (wcscmp(defdevid.get(), device_id) == 0);
     }
   }
 
   return ret;
 }
 
-static cubeb_device_info *
-wasapi_create_device(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
+static int
+wasapi_create_device(cubeb_device_info * ret, IMMDeviceEnumerator * enumerator, IMMDevice * dev)
 {
   com_ptr<IMMEndpoint> endpoint;
   com_ptr<IMMDevice> devnode;
   com_ptr<IAudioClient> client;
-  cubeb_device_info * ret = NULL;
   EDataFlow flow;
   DWORD state = DEVICE_STATE_NOTPRESENT;
   com_ptr<IPropertyStore> propstore;
   REFERENCE_TIME def_period, min_period;
   HRESULT hr;
 
   struct prop_variant : public PROPVARIANT {
     prop_variant() { PropVariantInit(this); }
     ~prop_variant() { PropVariantClear(this); }
     prop_variant(prop_variant const &) = delete;
     prop_variant & operator=(prop_variant const &) = delete;
   };
 
   hr = dev->QueryInterface(IID_PPV_ARGS(endpoint.receive()));
-  if (FAILED(hr)) return nullptr;
+  if (FAILED(hr)) return CUBEB_ERROR;
 
   hr = endpoint->GetDataFlow(&flow);
-  if (FAILED(hr)) return nullptr;
+  if (FAILED(hr)) return CUBEB_ERROR;
 
   wchar_t * tmp = nullptr;
   hr = dev->GetId(&tmp);
-  if (FAILED(hr)) return nullptr;
+  if (FAILED(hr)) return CUBEB_ERROR;
   com_heap_ptr<wchar_t> device_id(tmp);
 
   hr = dev->OpenPropertyStore(STGM_READ, propstore.receive());
-  if (FAILED(hr)) return nullptr;
+  if (FAILED(hr)) return CUBEB_ERROR;
 
   hr = dev->GetState(&state);
-  if (FAILED(hr)) return nullptr;
+  if (FAILED(hr)) return CUBEB_ERROR;
 
-  ret = (cubeb_device_info *)calloc(1, sizeof(cubeb_device_info));
-
+  XASSERT(ret);
   ret->device_id = wstr_to_utf8(device_id.get());
   ret->devid = reinterpret_cast<cubeb_devid>(ret->device_id);
   prop_variant namevar;
   hr = propstore->GetValue(PKEY_Device_FriendlyName, &namevar);
   if (SUCCEEDED(hr))
     ret->friendly_name = wstr_to_utf8(namevar.pwszVal);
 
   devnode = wasapi_get_device_node(enumerator, dev);
   if (devnode) {
     com_ptr<IPropertyStore> ps;
     hr = devnode->OpenPropertyStore(STGM_READ, ps.receive());
-    if (FAILED(hr)) return ret;
+    if (FAILED(hr)) return CUBEB_ERROR;
 
     prop_variant instancevar;
     hr = ps->GetValue(PKEY_Device_InstanceId, &instancevar);
     if (SUCCEEDED(hr)) {
       ret->group_id = wstr_to_utf8(instancevar.pwszVal);
     }
   }
 
@@ -2248,33 +2255,30 @@ wasapi_create_device(IMMDeviceEnumerator
       SUCCEEDED(client->GetDevicePeriod(&def_period, &min_period))) {
     ret->latency_lo = hns_to_frames(ret->default_rate, min_period);
     ret->latency_hi = hns_to_frames(ret->default_rate, def_period);
   } else {
     ret->latency_lo = 0;
     ret->latency_hi = 0;
   }
 
-  return ret;
+  return CUBEB_OK;
 }
 
 static int
 wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
-                         cubeb_device_collection ** out)
+                         cubeb_device_collection * out)
 {
   auto_com com;
   com_ptr<IMMDeviceEnumerator> enumerator;
   com_ptr<IMMDeviceCollection> collection;
-  cubeb_device_info * cur;
   HRESULT hr;
   UINT cc, i;
   EDataFlow flow;
 
-  *out = NULL;
-
   if (!com.ok())
     return CUBEB_ERROR;
 
   hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL,
       CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.receive()));
   if (FAILED(hr)) {
     LOG("Could not get device enumerator: %lx", hr);
     return CUBEB_ERROR;
@@ -2291,32 +2295,36 @@ wasapi_enumerate_devices(cubeb * context
     return CUBEB_ERROR;
   }
 
   hr = collection->GetCount(&cc);
   if (FAILED(hr)) {
     LOG("IMMDeviceCollection::GetCount() failed: %lx", hr);
     return CUBEB_ERROR;
   }
-  *out = (cubeb_device_collection *) malloc(sizeof(cubeb_device_collection) +
-      sizeof(cubeb_device_info*) * (cc > 0 ? cc - 1 : 0));
-  if (!*out) {
+  cubeb_device_info * devices =
+    (cubeb_device_info *) calloc(cc, sizeof(cubeb_device_info));
+  if (!devices) {
     return CUBEB_ERROR;
   }
-  (*out)->count = 0;
+  out->count = 0;
   for (i = 0; i < cc; i++) {
     com_ptr<IMMDevice> dev;
     hr = collection->Item(i, dev.receive());
     if (FAILED(hr)) {
       LOG("IMMDeviceCollection::Item(%u) failed: %lx", i-1, hr);
-    } else if ((cur = wasapi_create_device(enumerator.get(), dev.get())) != NULL) {
-      (*out)->device[(*out)->count++] = cur;
+      continue;
+    }
+    auto cur = &devices[out->count];
+    if (wasapi_create_device(cur, enumerator.get(), dev.get()) == CUBEB_OK) {
+      out->count += 1;
     }
   }
 
+  out->device = devices;
   return CUBEB_OK;
 }
 
 cubeb_ops const wasapi_ops = {
   /*.init =*/ wasapi_init,
   /*.get_backend_id =*/ wasapi_get_backend_id,
   /*.get_max_channel_count =*/ wasapi_get_max_channel_count,
   /*.get_min_latency =*/ wasapi_get_min_latency,
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -839,76 +839,62 @@ device_id_idx(UINT devid)
   char * ret = malloc(16);
   if (!ret) {
     return NULL;
   }
   _snprintf_s(ret, 16, _TRUNCATE, "%u", devid);
   return ret;
 }
 
-static cubeb_device_info *
-winmm_create_device_from_outcaps2(LPWAVEOUTCAPS2A caps, UINT devid)
+static void
+winmm_create_device_from_outcaps2(cubeb_device_info * ret, LPWAVEOUTCAPS2A caps, UINT devid)
 {
-  cubeb_device_info * ret;
-
-  ret = calloc(1, sizeof(cubeb_device_info));
-  if (!ret) {
-    return NULL;
-  }
+  XASSERT(ret);
   ret->devid = (cubeb_devid) devid;
   ret->device_id = device_id_idx(devid);
   ret->friendly_name = _strdup(caps->szPname);
   ret->group_id = guid_to_cstr(&caps->ProductGuid);
   ret->vendor_name = guid_to_cstr(&caps->ManufacturerGuid);
 
   ret->type = CUBEB_DEVICE_TYPE_OUTPUT;
   ret->state = CUBEB_DEVICE_STATE_ENABLED;
   ret->preferred = winmm_query_preferred_out_device(devid);
 
   ret->max_channels = caps->wChannels;
   winmm_calculate_device_rate(ret, caps->dwFormats);
   winmm_query_supported_formats(devid, caps->dwFormats,
       &ret->format, &ret->default_format);
 
-  /* Hardcoed latency estimates... */
+  /* Hardcoded latency estimates... */
   ret->latency_lo = 100 * ret->default_rate / 1000;
   ret->latency_hi = 200 * ret->default_rate / 1000;
-
-  return ret;
 }
 
-static cubeb_device_info *
-winmm_create_device_from_outcaps(LPWAVEOUTCAPSA caps, UINT devid)
+static void
+winmm_create_device_from_outcaps(cubeb_device_info * ret, LPWAVEOUTCAPSA caps, UINT devid)
 {
-  cubeb_device_info * ret;
-
-  ret = calloc(1, sizeof(cubeb_device_info));
-  if (!ret) {
-    return NULL;
-  }
+  XASSERT(ret);
   ret->devid = (cubeb_devid) devid;
   ret->device_id = device_id_idx(devid);
   ret->friendly_name = _strdup(caps->szPname);
   ret->group_id = NULL;
   ret->vendor_name = NULL;
 
   ret->type = CUBEB_DEVICE_TYPE_OUTPUT;
   ret->state = CUBEB_DEVICE_STATE_ENABLED;
   ret->preferred = winmm_query_preferred_out_device(devid);
 
   ret->max_channels = caps->wChannels;
   winmm_calculate_device_rate(ret, caps->dwFormats);
   winmm_query_supported_formats(devid, caps->dwFormats,
       &ret->format, &ret->default_format);
 
-  /* Hardcoed latency estimates... */
+  /* Hardcoded latency estimates... */
   ret->latency_lo = 100 * ret->default_rate / 1000;
   ret->latency_hi = 200 * ret->default_rate / 1000;
-
-  return ret;
 }
 
 static cubeb_device_pref
 winmm_query_preferred_in_device(UINT devid)
 {
   DWORD mmpref = WAVE_MAPPER, compref = WAVE_MAPPER, status;
   cubeb_device_pref ret = CUBEB_DEVICE_PREF_NONE;
 
@@ -920,131 +906,119 @@ winmm_query_preferred_in_device(UINT dev
   if (waveInMessage((HWAVEIN) WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
         (DWORD_PTR)&compref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
       devid == compref)
     ret |= CUBEB_DEVICE_PREF_VOICE;
 
   return ret;
 }
 
-static cubeb_device_info *
-winmm_create_device_from_incaps2(LPWAVEINCAPS2A caps, UINT devid)
+static void
+winmm_create_device_from_incaps2(cubeb_device_info * ret, LPWAVEINCAPS2A caps, UINT devid)
 {
-  cubeb_device_info * ret;
-
-  ret = calloc(1, sizeof(cubeb_device_info));
-  if (!ret) {
-    return NULL;
-  }
+  XASSERT(ret);
   ret->devid = (cubeb_devid) devid;
   ret->device_id = device_id_idx(devid);
   ret->friendly_name = _strdup(caps->szPname);
   ret->group_id = guid_to_cstr(&caps->ProductGuid);
   ret->vendor_name = guid_to_cstr(&caps->ManufacturerGuid);
 
   ret->type = CUBEB_DEVICE_TYPE_INPUT;
   ret->state = CUBEB_DEVICE_STATE_ENABLED;
   ret->preferred = winmm_query_preferred_in_device(devid);
 
   ret->max_channels = caps->wChannels;
   winmm_calculate_device_rate(ret, caps->dwFormats);
   winmm_query_supported_formats(devid, caps->dwFormats,
       &ret->format, &ret->default_format);
 
-  /* Hardcoed latency estimates... */
+  /* Hardcoded latency estimates... */
   ret->latency_lo = 100 * ret->default_rate / 1000;
   ret->latency_hi = 200 * ret->default_rate / 1000;
-
-  return ret;
 }
 
-static cubeb_device_info *
-winmm_create_device_from_incaps(LPWAVEINCAPSA caps, UINT devid)
+static void
+winmm_create_device_from_incaps(cubeb_device_info * ret, LPWAVEINCAPSA caps, UINT devid)
 {
-  cubeb_device_info * ret;
-
-  ret = calloc(1, sizeof(cubeb_device_info));
-  if (!ret) {
-    return NULL;
-  }
+  XASSERT(ret);
   ret->devid = (cubeb_devid) devid;
   ret->device_id = device_id_idx(devid);
   ret->friendly_name = _strdup(caps->szPname);
   ret->group_id = NULL;
   ret->vendor_name = NULL;
 
   ret->type = CUBEB_DEVICE_TYPE_INPUT;
   ret->state = CUBEB_DEVICE_STATE_ENABLED;
   ret->preferred = winmm_query_preferred_in_device(devid);
 
   ret->max_channels = caps->wChannels;
   winmm_calculate_device_rate(ret, caps->dwFormats);
   winmm_query_supported_formats(devid, caps->dwFormats,
       &ret->format, &ret->default_format);
 
-  /* Hardcoed latency estimates... */
+  /* Hardcoded latency estimates... */
   ret->latency_lo = 100 * ret->default_rate / 1000;
   ret->latency_hi = 200 * ret->default_rate / 1000;
-
-  return ret;
 }
 
 static int
 winmm_enumerate_devices(cubeb * context, cubeb_device_type type,
-                        cubeb_device_collection ** collection)
+                        cubeb_device_collection * collection)
 {
   UINT i, incount, outcount, total;
-  cubeb_device_info * cur;
+  cubeb_device_info * devices;
+  cubeb_device_info * dev;
 
   outcount = waveOutGetNumDevs();
   incount = waveInGetNumDevs();
   total = outcount + incount;
-  if (total > 0) {
-    total -= 1;
-  }
-  *collection = malloc(sizeof(cubeb_device_collection) +
-      sizeof(cubeb_device_info*) * total);
-  (*collection)->count = 0;
+
+  devices = calloc(total, sizeof(cubeb_device_info));
+  collection->count = 0;
 
   if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
     WAVEOUTCAPSA woc;
     WAVEOUTCAPS2A woc2;
 
     ZeroMemory(&woc, sizeof(woc));
     ZeroMemory(&woc2, sizeof(woc2));
 
     for (i = 0; i < outcount; i++) {
-      if ((waveOutGetDevCapsA(i, (LPWAVEOUTCAPSA)&woc2, sizeof(woc2)) == MMSYSERR_NOERROR &&
-            (cur = winmm_create_device_from_outcaps2(&woc2, i)) != NULL) ||
-          (waveOutGetDevCapsA(i, &woc, sizeof(woc)) == MMSYSERR_NOERROR &&
-            (cur = winmm_create_device_from_outcaps(&woc, i)) != NULL)
-          ) {
-        (*collection)->device[(*collection)->count++] = cur;
+      dev = &devices[collection->count];
+      if (waveOutGetDevCapsA(i, (LPWAVEOUTCAPSA)&woc2, sizeof(woc2)) == MMSYSERR_NOERROR) {
+        winmm_create_device_from_outcaps2(dev, &woc2, i);
+        collection->count += 1;
+      } else if (waveOutGetDevCapsA(i, &woc, sizeof(woc)) == MMSYSERR_NOERROR) {
+        winmm_create_device_from_outcaps(dev, &woc, i);
+        collection->count += 1;
       }
     }
   }
 
   if (type & CUBEB_DEVICE_TYPE_INPUT) {
     WAVEINCAPSA wic;
     WAVEINCAPS2A wic2;
 
     ZeroMemory(&wic, sizeof(wic));
     ZeroMemory(&wic2, sizeof(wic2));
 
     for (i = 0; i < incount; i++) {
-      if ((waveInGetDevCapsA(i, (LPWAVEINCAPSA)&wic2, sizeof(wic2)) == MMSYSERR_NOERROR &&
-            (cur = winmm_create_device_from_incaps2(&wic2, i)) != NULL) ||
-          (waveInGetDevCapsA(i, &wic, sizeof(wic)) == MMSYSERR_NOERROR &&
-            (cur = winmm_create_device_from_incaps(&wic, i)) != NULL)
-          ) {
-        (*collection)->device[(*collection)->count++] = cur;
+      dev = &devices[collection->count];
+      if (waveInGetDevCapsA(i, (LPWAVEINCAPSA)&wic2, sizeof(wic2)) == MMSYSERR_NOERROR) {
+        winmm_create_device_from_incaps2(dev, &wic2, i);
+        collection->count += 1;
+      } else if (waveInGetDevCapsA(i, &wic, sizeof(wic)) == MMSYSERR_NOERROR) {
+        winmm_create_device_from_incaps(dev, &wic, i);
+        collection->count += 1;
       }
     }
   }
 
+  collection->device = devices;
+
   return CUBEB_OK;
 }
 
 static struct cubeb_ops const winmm_ops = {
   /*.init =*/ winmm_init,
   /*.get_backend_id =*/ winmm_get_backend_id,
   /*.get_max_channel_count=*/ winmm_get_max_channel_count,
   /*.get_min_latency=*/ winmm_get_min_latency,