Backed out changeset 359999c77a46 (bug 1314514) for build bustage a=backout CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Tue, 15 Nov 2016 12:03:51 -0800
changeset 367748 ea07c491499006c6650fbd75431a393c4f4d124d
parent 367747 0cc3a3f1c16a591228b0d6926fdc29ef67ffaeb7
child 367749 07fa89dfac8390c8529181cbf818b6e5c1a75bf1
push id6996
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 20:48:21 +0000
treeherdermozilla-beta@d89512dab048 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs1314514
milestone53.0a1
backs out359999c77a46de239e61e84d1df532bb3239c7d5
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
Backed out changeset 359999c77a46 (bug 1314514) for build bustage a=backout CLOSED TREE
media/libcubeb/README_MOZILLA
media/libcubeb/gtest/common.h
media/libcubeb/gtest/moz.build
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_record.cpp
media/libcubeb/gtest/test_resampler.cpp
media/libcubeb/gtest/test_ring_array.cpp
media/libcubeb/gtest/test_sanity.cpp
media/libcubeb/gtest/test_tone.cpp
media/libcubeb/gtest/test_utils.cpp
media/libcubeb/include/cubeb.h
media/libcubeb/moz.build
media/libcubeb/src/cubeb.c
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_jack.cpp
media/libcubeb/src/cubeb_pulse.c
media/libcubeb/src/cubeb_resampler_internal.h
media/libcubeb/src/cubeb_wasapi.cpp
media/libcubeb/src/cubeb_winmm.c
media/libcubeb/tests/common.h
media/libcubeb/tests/moz.build
media/libcubeb/tests/test_audio.cpp
media/libcubeb/tests/test_devices.cpp
media/libcubeb/tests/test_duplex.cpp
media/libcubeb/tests/test_latency.cpp
media/libcubeb/tests/test_record.cpp
media/libcubeb/tests/test_resampler.cpp
media/libcubeb/tests/test_sanity.cpp
media/libcubeb/tests/test_tone.cpp
media/libcubeb/tests/test_utils.cpp
media/libcubeb/update.sh
testing/cppunittest.ini
--- 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 8bab182cd70ff66dec5bbecb69a69422f5d57647.
+The git commit ID used was f8467510a8b36793b1b8b7e85461e2e189eb7015.
deleted file mode 100644
--- a/media/libcubeb/gtest/test_latency.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "gtest/gtest.h"
-#include <stdlib.h>
-#include "cubeb/cubeb.h"
-
-TEST(cubeb, latency)
-{
-  cubeb * ctx = NULL;
-  int r;
-  uint32_t max_channels;
-  uint32_t preferred_rate;
-  uint32_t latency_frames;
-
-  r = cubeb_init(&ctx, "Cubeb audio test");
-  ASSERT_EQ(r, CUBEB_OK);
-
-  r = cubeb_get_max_channel_count(ctx, &max_channels);
-  ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
-  if (r == CUBEB_OK) {
-    ASSERT_GT(max_channels, 0u);
-  }
-
-  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);
-  }
-
-  cubeb_stream_params params = {
-    CUBEB_SAMPLE_FLOAT32NE,
-    preferred_rate,
-    max_channels
-  };
-  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);
-  }
-
-  cubeb_destroy(ctx);
-}
deleted file mode 100644
--- a/media/libcubeb/gtest/test_ring_array.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-#include "gtest/gtest.h"
-#ifdef __APPLE__
-#include <string.h>
-#include <iostream>
-#include <CoreAudio/CoreAudioTypes.h>
-#include "cubeb/cubeb.h"
-#include "cubeb_ring_array.h"
-
-TEST(cubeb, ring_array)
-{
-  ring_array ra;
-
-  ASSERT_EQ(ring_array_init(&ra, 0, 0, 1, 1), CUBEB_ERROR_INVALID_PARAMETER);
-  ASSERT_EQ(ring_array_init(&ra, 1, 0, 0, 1), CUBEB_ERROR_INVALID_PARAMETER);
-
-  unsigned int capacity = 8;
-  ring_array_init(&ra, capacity, sizeof(int), 1, 1);
-  int verify_data[capacity] ;// {1,2,3,4,5,6,7,8};
-  AudioBuffer * p_data = NULL;
-
-  for (unsigned int i = 0; i < capacity; ++i) {
-    verify_data[i] = i; // in case capacity change value
-    *(int*)ra.buffer_array[i].mData = i;
-    ASSERT_EQ(ra.buffer_array[i].mDataByteSize, sizeof(int));
-    ASSERT_EQ(ra.buffer_array[i].mNumberChannels, 1u);
-  }
-
-  /* Get store buffers*/
-  for (unsigned int i = 0; i < capacity; ++i) {
-    p_data = ring_array_get_free_buffer(&ra);
-    ASSERT_NE(p_data, nullptr);
-    ASSERT_EQ(*(int*)p_data->mData, verify_data[i]);
-  }
-  /*Now array is full extra store should give NULL*/
-  ASSERT_EQ(ring_array_get_free_buffer(&ra), nullptr);
-  /* Get fetch buffers*/
-  for (unsigned int i = 0; i < capacity; ++i) {
-    p_data = ring_array_get_data_buffer(&ra);
-    ASSERT_NE(p_data, nullptr);
-    ASSERT_EQ(*(int*)p_data->mData, verify_data[i]);
-  }
-  /*Now array is empty extra fetch should give NULL*/
-  ASSERT_EQ(ring_array_get_data_buffer(&ra), nullptr);
-
-  p_data = NULL;
-  /* Repeated store fetch should can go for ever*/
-  for (unsigned int i = 0; i < 2*capacity; ++i) {
-    p_data = ring_array_get_free_buffer(&ra);
-    ASSERT_NE(p_data, nullptr);
-    ASSERT_EQ(ring_array_get_data_buffer(&ra), p_data);
-  }
-
-  p_data = NULL;
-  /* Verify/modify buffer data*/
-  for (unsigned int i = 0; i < capacity; ++i) {
-    p_data = ring_array_get_free_buffer(&ra);
-    ASSERT_NE(p_data, nullptr);
-    ASSERT_EQ(*((int*)p_data->mData), verify_data[i]);
-    (*((int*)p_data->mData))++; // Modify data
-  }
-  for (unsigned int i = 0; i < capacity; ++i) {
-    p_data = ring_array_get_data_buffer(&ra);
-    ASSERT_NE(p_data, nullptr);
-    ASSERT_EQ(*((int*)p_data->mData), verify_data[i]+1); // Verify modified data
-  }
-
-  ring_array_destroy(&ra);
-}
-#else
-TEST(cubeb, DISABLED_ring_array)
-{
-}
-#endif
deleted file mode 100644
--- a/media/libcubeb/gtest/test_utils.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-#include "gtest/gtest.h"
-#include "cubeb_utils.h"
-
-TEST(cubeb, auto_array)
-{
-  auto_array<uint32_t> array;
-  auto_array<uint32_t> array2(10);
-  uint32_t a[10];
-
-  ASSERT_EQ(array2.length(), 0u);
-  ASSERT_EQ(array2.capacity(), 10u);
-
-
-  for (uint32_t i = 0; i < 10; i++) {
-    a[i] = i;
-  }
-
-  ASSERT_EQ(array.capacity(), 0u);
-  ASSERT_EQ(array.length(), 0u);
-
-  array.push(a, 10);
-
-  ASSERT_TRUE(!array.reserve(9));
-
-  for (uint32_t i = 0; i < 10; i++) {
-    ASSERT_EQ(array.data()[i], i);
-  }
-
-  ASSERT_EQ(array.capacity(), 10u);
-  ASSERT_EQ(array.length(), 10u);
-
-  uint32_t b[10];
-
-  array.pop(b, 5);
-
-  ASSERT_EQ(array.capacity(), 10u);
-  ASSERT_EQ(array.length(), 5u);
-  for (uint32_t i = 0; i < 5; i++) {
-    ASSERT_EQ(b[i], i);
-    ASSERT_EQ(array.data()[i], 5 + i);
-  }
-  uint32_t* bb = b + 5;
-  array.pop(bb, 5);
-
-  ASSERT_EQ(array.capacity(), 10u);
-  ASSERT_EQ(array.length(), 0u);
-  for (uint32_t i = 0; i < 5; i++) {
-    ASSERT_EQ(bb[i], 5 + i);
-  }
-
-  ASSERT_TRUE(!array.pop(nullptr, 1));
-
-  array.push(a, 10);
-  array.push(a, 10);
-
-  for (uint32_t j = 0; j < 2; j++) {
-    for (uint32_t i = 0; i < 10; i++) {
-      ASSERT_EQ(array.data()[10 * j + i], i);
-    }
-  }
-  ASSERT_EQ(array.length(), 20u);
-  ASSERT_EQ(array.capacity(), 20u);
-  array.pop(nullptr, 5);
-
-  for (uint32_t i = 0; i < 5; i++) {
-    ASSERT_EQ(array.data()[i], 5 + i);
-  }
-
-  ASSERT_EQ(array.length(), 15u);
-  ASSERT_EQ(array.capacity(), 20u);
-}
-
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -162,17 +162,17 @@ typedef enum {
     CUBEB_STREAM_TYPE_FM = 10,
 
     CUBEB_STREAM_TYPE_MAX
 } cubeb_stream_type;
 #endif
 
 /** An opaque handle used to refer a particular input or output device
  *  across calls. */
-typedef void const * cubeb_devid;
+typedef void * cubeb_devid;
 
 /** Level (verbosity) of logging for a particular cubeb context. */
 typedef enum {
   CUBEB_LOG_DISABLED = 0, /** < Logging disabled */
   CUBEB_LOG_NORMAL = 1, /**< Logging lifetime operation (creation/destruction). */
   CUBEB_LOG_VERBOSE = 2, /**< Verbose logging of callbacks, can have performance implications. */
 } cubeb_log_level;
 
@@ -271,20 +271,20 @@ typedef enum {
 } cubeb_device_pref;
 
 /** This structure holds the characteristics
  *  of an input or output audio device. It can be obtained using
  *  `cubeb_enumerate_devices`, and must be destroyed using
  *  `cubeb_device_info_destroy`. */
 typedef struct {
   cubeb_devid devid;          /**< Device identifier handle. */
-  char const * device_id;     /**< Device identifier which might be presented in a UI. */
-  char const * friendly_name; /**< Friendly device name which might be presented in a UI. */
-  char const * group_id;      /**< Two devices have the same group identifier if they belong to the same physical device; for example a headset and microphone. */
-  char const * vendor_name;   /**< Optional vendor name, may be NULL. */
+  char * device_id;           /**< Device identifier which might be presented in a UI. */
+  char * friendly_name;       /**< Friendly device name which might be presented in a UI. */
+  char * group_id;            /**< Two devices have the same group identifier if they belong to the same physical device; for example a headset and microphone. */
+  char * 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. */
@@ -317,17 +317,17 @@ typedef struct {
                          or nullptr if this is an input-only stream.
     @param nframes The number of frames of the two buffer.
     @retval Number of frames written to the output buffer. If this number is
             less than nframes, then the stream will start to drain.
     @retval CUBEB_ERROR on error, in which case the data callback will stop
             and the stream will enter a shutdown state. */
 typedef long (* cubeb_data_callback)(cubeb_stream * stream,
                                      void * user_ptr,
-                                     void const * input_buffer,
+                                     const void * input_buffer,
                                      void * output_buffer,
                                      long nframes);
 
 /** User supplied state callback.
     @param stream The stream for this this callback fired.
     @param user_ptr The pointer passed to cubeb_stream_init.
     @param state The new state of the stream. */
 typedef void (* cubeb_state_callback)(cubeb_stream * stream,
@@ -342,17 +342,17 @@ typedef void (* cubeb_device_changed_cal
 /**
  * User supplied callback called when the underlying device collection changed.
  * @param context A pointer to the cubeb context.
  * @param user_ptr The pointer passed to cubeb_stream_init. */
 typedef void (* cubeb_device_collection_changed_callback)(cubeb * context,
                                                           void * user_ptr);
 
 /** User supplied callback called when a message needs logging. */
-typedef void (* cubeb_log_callback)(char const * fmt, ...);
+typedef void (* cubeb_log_callback)(const char * fmt, ...);
 
 /** Initialize an application context.  This will perform any library or
     application scoped initialization.
     @param context A out param where an opaque pointer to the application
                    context will be returned.
     @param context_name A name for the context. Depending on the platform this
                         can appear in different locations.
     @retval CUBEB_OK in case of success.
--- a/media/libcubeb/moz.build
+++ b/media/libcubeb/moz.build
@@ -1,9 +1,9 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['include', 'src']
-TEST_DIRS += ['gtest']
+TEST_DIRS += ['tests']
 
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -509,20 +509,20 @@ int cubeb_device_collection_destroy(cube
 }
 
 int cubeb_device_info_destroy(cubeb_device_info * info)
 {
   if (info == NULL) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
-  free((void *) info->device_id);
-  free((void *) info->friendly_name);
-  free((void *) info->group_id);
-  free((void *) info->vendor_name);
+  free(info->device_id);
+  free(info->friendly_name);
+  free(info->group_id);
+  free(info->vendor_name);
 
   free(info);
   return CUBEB_OK;
 }
 
 int cubeb_register_device_collection_changed(cubeb * context,
                                              cubeb_device_type devtype,
                                              cubeb_device_collection_changed_callback callback,
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -163,19 +163,19 @@ private:
 struct cubeb_stream {
   cubeb * context;
   cubeb_data_callback data_callback;
   cubeb_state_callback state_callback;
   cubeb_device_changed_callback device_changed_callback;
   /* Stream creation parameters */
   cubeb_stream_params input_stream_params;
   cubeb_stream_params output_stream_params;
+  cubeb_devid input_device;
   bool is_default_input;
-  AudioDeviceID input_device;
-  AudioDeviceID output_device;
+  cubeb_devid output_device;
   /* User pointer of data_callback */
   void * user_ptr;
   /* Format descriptions */
   AudioStreamBasicDescription input_desc;
   AudioStreamBasicDescription output_desc;
   /* I/O AudioUnits */
   AudioUnit input_unit;
   AudioUnit output_unit;
@@ -187,17 +187,17 @@ struct cubeb_stream {
   int expected_output_callbacks_in_a_row;
   owned_critical_section mutex;
   /* Hold the input samples in every
    * input callback iteration */
   auto_array_wrapper * input_linear_buffer;
   /* Frames on input buffer */
   std::atomic<uint32_t> input_buffer_frames;
   /* Frame counters */
-  std::atomic<uint64_t> frames_played;
+  uint64_t frames_played;
   uint64_t frames_queued;
   std::atomic<int64_t> frames_read;
   std::atomic<bool> shutdown;
   std::atomic<bool> draining;
   /* Latency requested by the user. */
   uint32_t latency_frames;
   std::atomic<uint64_t> current_latency_frames;
   uint64_t hw_latency_frames;
@@ -596,35 +596,35 @@ audiounit_property_listener_callback(Aud
   was_running = !stm->shutdown;
 
   LOG("(%p) Audio device changed, %d events.", stm, address_count);
   for (UInt32 i = 0; i < address_count; i++) {
     switch(addresses[i].mSelector) {
       case kAudioHardwarePropertyDefaultOutputDevice: {
           LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i);
           // Allow restart to choose the new default
-          stm->output_device = 0;
+          stm->output_device = nullptr;
         }
         break;
       case kAudioHardwarePropertyDefaultInputDevice: {
           LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultInputDevice", i);
           // Allow restart to choose the new default
-          stm->input_device = 0;
+          stm->input_device = nullptr;
         }
       break;
       case kAudioDevicePropertyDeviceIsAlive: {
           LOG("Event[%d] - mSelector == kAudioDevicePropertyDeviceIsAlive", i);
           // If this is the default input device ignore the event,
           // kAudioHardwarePropertyDefaultInputDevice will take care of the switch
           if (stm->is_default_input) {
             LOG("It's the default input device, ignore the event");
             return noErr;
           }
           // Allow restart to choose the new default. Event register only for input.
-          stm->input_device = 0;
+          stm->input_device = nullptr;
         }
         break;
       case kAudioDevicePropertyDataSource:
         LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
         break;
     }
   }
 
@@ -753,17 +753,17 @@ audiounit_install_device_changed_callbac
     r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
         kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
       return CUBEB_ERROR;
     }
 
     /* Event to notify when the input is going away. */
-    AudioDeviceID dev = stm->input_device ? stm->input_device :
+    AudioDeviceID dev = stm->input_device ? reinterpret_cast<intptr_t>(stm->input_device) :
                                             audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
         kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
       return CUBEB_ERROR;
     }
   }
@@ -1038,34 +1038,34 @@ audio_stream_desc_init(AudioStreamBasicD
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_create_unit(AudioUnit * unit,
                       bool is_input,
                       const cubeb_stream_params * /* stream_params */,
-                      AudioDeviceID device)
+                      cubeb_devid device)
 {
   AudioComponentDescription desc;
   AudioComponent comp;
   UInt32 enable;
   AudioDeviceID devid;
   OSStatus rv;
 
   desc.componentType = kAudioUnitType_Output;
 #if TARGET_OS_IPHONE
   bool use_default_output = false;
   desc.componentSubType = kAudioUnitSubType_RemoteIO;
 #else
   // Use the DefaultOutputUnit for output when no device is specified
   // so we retain automatic output device switching when the default
   // changes.  Once we have complete support for device notifications
   // and switching, we can use the AUHAL for everything.
-  bool use_default_output = device == 0 && !is_input;
+  bool use_default_output = device == NULL && !is_input;
   if (use_default_output) {
     desc.componentSubType = kAudioUnitSubType_DefaultOutput;
   } else {
     desc.componentSubType = kAudioUnitSubType_HALOutput;
   }
 #endif
   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
   desc.componentFlags = 0;
@@ -1096,21 +1096,21 @@ audiounit_create_unit(AudioUnit * unit,
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
                               is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
                               is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
     if (rv != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
       return CUBEB_ERROR;
     }
 
-    if (device == 0) {
+    if (device == NULL) {
       assert(is_input);
       devid = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     } else {
-      devid = device;
+      devid = reinterpret_cast<intptr_t>(device);
     }
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
                               kAudioUnitScope_Global,
                               is_input ? AU_IN_BUS : AU_OUT_BUS,
                               &devid, sizeof(AudioDeviceID));
     if (rv != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
       return CUBEB_ERROR;
@@ -1555,23 +1555,24 @@ audiounit_stream_init(cubeb * context,
    * full-duplex stream and different devices for input vs output. */
   stm->context = context;
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   stm->device_changed_callback = NULL;
   if (input_stream_params) {
     stm->input_stream_params = *input_stream_params;
-    stm->input_device = reinterpret_cast<uintptr_t>(input_device);
-    stm->is_default_input = stm->input_device == 0 ||
-                            (audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT) == stm->input_device);
+    stm->input_device = input_device;
+    stm->is_default_input = input_device == nullptr ||
+                            (audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT) ==
+                                                  reinterpret_cast<intptr_t>(input_device));
   }
   if (output_stream_params) {
     stm->output_stream_params = *output_stream_params;
-    stm->output_device = reinterpret_cast<uintptr_t>(output_device);
+    stm->output_device = output_device;
   }
 
   /* Init data members where necessary */
   stm->hw_latency_frames = UINT64_MAX;
 
   /* Silently clamp the latency down to the platform default, because we
    * synthetize the clock from the callbacks, and we want the clock to update
    * often. */
@@ -1815,17 +1816,17 @@ int audiounit_stream_set_panning(cubeb_s
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
   stm->panning.store(panning, std::memory_order_relaxed);
   return CUBEB_OK;
 }
 
 int audiounit_stream_get_current_device(cubeb_stream * stm,
-                                        cubeb_device ** const device)
+                                        cubeb_device ** const  device)
 {
 #if TARGET_OS_IPHONE
   //TODO
   return CUBEB_ERROR_NOT_SUPPORTED;
 #else
   OSStatus r;
   UInt32 size;
   UInt32 data;
@@ -2105,18 +2106,17 @@ audiounit_create_device_from_hwdev(Audio
 
   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->devid = (cubeb_devid)(size_t)devid;
     ret->group_id = strdup(ret->device_id);
     CFRelease(str);
   }
 
   size = sizeof(CFStringRef);
   adr.mSelector = kAudioObjectPropertyName;
   if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &str) == noErr && str != NULL) {
     UInt32 ds;
--- a/media/libcubeb/src/cubeb_jack.cpp
+++ b/media/libcubeb/src/cubeb_jack.cpp
@@ -988,19 +988,19 @@ cbjack_enumerate_devices(cubeb * context
   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";
 
   if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
-    context->devinfo[i] = (cubeb_device_info *) malloc(sizeof(cubeb_device_info));
+    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]->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;
@@ -1009,19 +1009,19 @@ cbjack_enumerate_devices(cubeb * context
     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++;
   }
 
   if (type & CUBEB_DEVICE_TYPE_INPUT) {
-    context->devinfo[i] = (cubeb_device_info *) malloc(sizeof(cubeb_device_info));
+    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]->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;
--- a/media/libcubeb/src/cubeb_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -176,19 +176,19 @@ stream_state_change_callback(cubeb_strea
   stm->state = s;
   stm->state_callback(stm, stm->user_ptr, s);
 }
 
 static void
 stream_drain_callback(pa_mainloop_api * a, pa_time_event * e, struct timeval const * tv, void * u)
 {
   (void)a;
+  (void)e;
   (void)tv;
   cubeb_stream * stm = u;
-  assert(stm->drain_timer == e);
   stream_state_change_callback(stm, CUBEB_STATE_DRAINED);
   /* there's no pa_rttime_free, so use this instead. */
   a->time_free(stm->drain_timer);
   stm->drain_timer = NULL;
   WRAP(pa_threaded_mainloop_signal)(stm->context->mainloop, 0);
 }
 
 static void
@@ -262,17 +262,16 @@ trigger_user_callback(pa_stream * s, voi
       r = WRAP(pa_stream_get_latency)(s, &latency, NULL);
       if (r == -PA_ERR_NODATA) {
         /* this needs a better guess. */
         latency = 100 * PA_USEC_PER_MSEC;
       }
       assert(r == 0 || r == -PA_ERR_NODATA);
       /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
       /* arbitrary safety margin: double the current latency. */
-      assert(!stm->drain_timer);
       stm->drain_timer = WRAP(pa_context_rttime_new)(stm->context->context, WRAP(pa_rtclock_now)() + 2 * latency, stream_drain_callback, stm);
       stm->shutdown = 1;
       return;
     }
 
     towrite -= size;
   }
 
@@ -748,17 +747,17 @@ pulse_stream_init(cubeb * context,
 
     stm->output_sample_spec = *(WRAP(pa_stream_get_sample_spec)(stm->output_stream));
 
     WRAP(pa_stream_set_state_callback)(stm->output_stream, stream_state_callback, stm);
     WRAP(pa_stream_set_write_callback)(stm->output_stream, stream_write_callback, stm);
 
     battr = set_buffering_attribute(latency_frames, &stm->output_sample_spec);
     WRAP(pa_stream_connect_playback)(stm->output_stream,
-                                     (char const *) output_device,
+                                     output_device,
                                      &battr,
                                      PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
                                      PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY,
                                      NULL, NULL);
   }
 
   // Set up input stream
   if (input_stream_params) {
@@ -771,17 +770,17 @@ pulse_stream_init(cubeb * context,
 
     stm->input_sample_spec = *(WRAP(pa_stream_get_sample_spec)(stm->input_stream));
 
     WRAP(pa_stream_set_state_callback)(stm->input_stream, stream_state_callback, stm);
     WRAP(pa_stream_set_read_callback)(stm->input_stream, stream_read_callback, stm);
 
     battr = set_buffering_attribute(latency_frames, &stm->input_sample_spec);
     WRAP(pa_stream_connect_record)(stm->input_stream,
-                                   (char const *) input_device,
+                                   input_device,
                                    &battr,
                                    PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
                                    PA_STREAM_START_CORKED | PA_STREAM_ADJUST_LATENCY);
   }
 
   r = wait_until_stream_ready(stm);
   if (r == 0) {
     /* force a timing update now, otherwise timing info does not become valid
@@ -847,19 +846,16 @@ pulse_stream_destroy(cubeb_stream * stm)
   free(stm);
 }
 
 static void
 pulse_defer_event_cb(pa_mainloop_api * a, void * userdata)
 {
   (void)a;
   cubeb_stream * stm = userdata;
-  if (stm->shutdown) {
-    return;
-  }
   size_t writable_size = WRAP(pa_stream_writable_size)(stm->output_stream);
   trigger_user_callback(stm->output_stream, NULL, writable_size, stm);
 }
 
 static int
 pulse_stream_start(cubeb_stream * stm)
 {
   stm->shutdown = 0;
@@ -1069,31 +1065,31 @@ pulse_get_state_from_sink_port(pa_sink_p
       return CUBEB_DEVICE_STATE_ENABLED;
   }
 
   return CUBEB_DEVICE_STATE_DISABLED;
 }
 
 static void
 pulse_sink_info_cb(pa_context * context, const pa_sink_info * info,
-                   int eol, void * user_data)
+    int eol, void * user_data)
 {
   pulse_dev_list_data * list_data = user_data;
   cubeb_device_info * devinfo;
   const char * prop;
 
   (void)context;
 
   if (eol || info == NULL)
     return;
 
   devinfo = calloc(1, sizeof(cubeb_device_info));
 
   devinfo->device_id = strdup(info->name);
-  devinfo->devid = (cubeb_devid) devinfo->device_id;
+  devinfo->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);
 
@@ -1143,17 +1139,17 @@ pulse_source_info_cb(pa_context * contex
   (void)context;
 
   if (eol)
     return;
 
   devinfo = calloc(1, sizeof(cubeb_device_info));
 
   devinfo->device_id = strdup(info->name);
-  devinfo->devid = (cubeb_devid) devinfo->device_id;
+  devinfo->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);
 
--- a/media/libcubeb/src/cubeb_resampler_internal.h
+++ b/media/libcubeb/src/cubeb_resampler_internal.h
@@ -258,25 +258,19 @@ public:
   }
 
   /** Returns the number of frames to pass in the input of the resampler to have
    * exactly `output_frame_count` resampled frames. This can return a number
    * slightly bigger than what is strictly necessary, but it guaranteed that the
    * number of output frames will be exactly equal. */
   uint32_t input_needed_for_output(uint32_t output_frame_count)
   {
-    int32_t unresampled_frames_left = samples_to_frames(resampling_in_buffer.length());
-    int32_t resampled_frames_left = samples_to_frames(resampling_out_buffer.length());
-    float input_frames_needed =
-      (output_frame_count - unresampled_frames_left) * resampling_ratio
-        - resampled_frames_left;
-    if (input_frames_needed < 0) {
-      return 0;
-    }
-    return (uint32_t)ceilf(input_frames_needed);
+    return (uint32_t)ceilf((output_frame_count - samples_to_frames(resampling_out_buffer.length()))
+                           * resampling_ratio);
+
   }
 
   /** Returns a pointer to the input buffer, that contains empty space for at
    * least `frame_count` elements. This is useful so that consumer can directly
    * write into the input buffer of the resampler. The pointer returned is
    * adjusted so that leftover data are not overwritten.
    */
   T * input_buffer(size_t frame_count)
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -17,17 +17,16 @@
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <cmath>
 #include <algorithm>
 #include <memory>
 #include <limits>
-#include <atomic>
 
 #include "cubeb/cubeb.h"
 #include "cubeb-internal.h"
 #include "cubeb_resampler.h"
 #include "cubeb_utils.h"
 
 /* devicetopology.h missing in MinGW. */
 #ifndef __devicetopology_h__
@@ -101,18 +100,18 @@ typedef HANDLE (WINAPI *set_mm_thread_ch
 typedef BOOL (WINAPI *revert_mm_thread_characteristics_function)(HANDLE handle);
 
 extern cubeb_ops const wasapi_ops;
 
 int wasapi_stream_stop(cubeb_stream * stm);
 int wasapi_stream_start(cubeb_stream * stm);
 void close_wasapi_stream(cubeb_stream * stm);
 int setup_wasapi_stream(cubeb_stream * stm);
-static char const * wstr_to_utf8(wchar_t const * str);
-static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
+static char * wstr_to_utf8(const wchar_t * str);
+static std::unique_ptr<const wchar_t[]> utf8_to_wstr(char* str);
 
 }
 
 struct cubeb
 {
   cubeb_ops const * ops;
   /* Library dynamically opened to increase the render thread priority, and
      the two function pointers we need. */
@@ -140,18 +139,18 @@ struct cubeb_stream
      itself. */
   cubeb_stream_params input_mix_params;
   cubeb_stream_params output_mix_params;
   /* Stream parameters. This is what the client requested,
    * and what will be presented in the callback. */
   cubeb_stream_params input_stream_params;
   cubeb_stream_params output_stream_params;
   /* The input and output device, or NULL for default. */
-  std::unique_ptr<const wchar_t[]> input_device;
-  std::unique_ptr<const wchar_t[]> output_device;
+  cubeb_devid input_device;
+  cubeb_devid output_device;
   /* The latency initially requested for this stream, in frames. */
   unsigned latency;
   cubeb_state_callback state_callback;
   cubeb_data_callback data_callback;
   wasapi_refill_callback refill_callback;
   void * user_ptr;
   /* Lifetime considerations:
      - client, render_client, audio_clock and audio_stream_volume are interface
@@ -216,21 +215,19 @@ struct cubeb_stream
   /* WASAPI input works in "packets". We re-linearize the audio packets
    * into this buffer before handing it to the resampler. */
   auto_array<float> linear_input_buffer;
   /* Stream volume.  Set via stream_set_volume and used to reset volume on
      device changes. */
   float volume;
   /* True if the stream is draining. */
   bool draining;
-  /* True when we've destroyed the stream. This pointer is leaked on stream
-   * destruction if we could not join the thread. */
-  std::atomic<std::atomic<bool>*> emergency_bailout;
 };
 
+
 class wasapi_endpoint_notification_client : public IMMNotificationClient
 {
 public:
   /* The implementation of MSCOM was copied from MSDN. */
   ULONG STDMETHODCALLTYPE
   AddRef()
   {
     return InterlockedIncrement(&ref_count);
@@ -779,17 +776,16 @@ refill_callback_output(cubeb_stream * st
 
   return got == output_frames || stm->draining;
 }
 
 static unsigned int __stdcall
 wasapi_stream_render_loop(LPVOID stream)
 {
   cubeb_stream * stm = static_cast<cubeb_stream *>(stream);
-  std::atomic<bool> * emergency_bailout = stm->emergency_bailout;
 
   bool is_playing = true;
   HANDLE wait_array[4] = {
     stm->shutdown_event,
     stm->reconfigure_event,
     stm->refill_event,
     stm->input_available_event
   };
@@ -819,20 +815,16 @@ wasapi_stream_render_loop(LPVOID stream)
      reset on each successful loop. */
   unsigned timeout_count = 0;
   const unsigned timeout_limit = 5;
   while (is_playing) {
     DWORD waitResult = WaitForMultipleObjects(ARRAY_LENGTH(wait_array),
                                               wait_array,
                                               FALSE,
                                               1000);
-    if (*emergency_bailout) {
-      delete emergency_bailout;
-      return 0;
-    }
     if (waitResult != WAIT_TIMEOUT) {
       timeout_count = 0;
     }
     switch (waitResult) {
     case WAIT_OBJECT_0: { /* shutdown */
       is_playing = false;
       /* We don't check if the drain is actually finished here, we just want to
          shutdown. */
@@ -1137,56 +1129,49 @@ int wasapi_init(cubeb ** context, char c
 
   *context = ctx;
 
   return CUBEB_OK;
 }
 }
 
 namespace {
-bool stop_and_join_render_thread(cubeb_stream * stm)
+void stop_and_join_render_thread(cubeb_stream * stm)
 {
-  bool rv = true;
   LOG("Stop and join render thread.");
   if (!stm->thread) {
     LOG("No thread present.");
-    return true;
+    return;
   }
 
   BOOL ok = SetEvent(stm->shutdown_event);
   if (!ok) {
     LOG("Destroy SetEvent failed: %d", GetLastError());
   }
 
   /* Wait five seconds for the rendering thread to return. It's supposed to
    * check its event loop very often, five seconds is rather conservative. */
   DWORD r = WaitForSingleObject(stm->thread, 5000);
   if (r == WAIT_TIMEOUT) {
     /* Something weird happened, leak the thread and continue the shutdown
      * process. */
-    *(stm->emergency_bailout) = true;
     LOG("Destroy WaitForSingleObject on thread timed out,"
         " leaking the thread: %d", GetLastError());
-    rv = false;
   }
   if (r == WAIT_FAILED) {
-    *(stm->emergency_bailout) = true;
     LOG("Destroy WaitForSingleObject on thread failed: %d", GetLastError());
-    rv = false;
   }
 
   LOG("Closing thread.");
 
   CloseHandle(stm->thread);
   stm->thread = NULL;
 
   CloseHandle(stm->shutdown_event);
   stm->shutdown_event = 0;
-
-  return rv;
 }
 
 void wasapi_destroy(cubeb * context)
 {
   if (context->mmcss_module) {
     FreeLibrary(context->mmcss_module);
   }
   free(context);
@@ -1405,17 +1390,17 @@ handle_channel_layout(cubeb_stream * stm
   }
 }
 
 #define DIRECTION_NAME (direction == eCapture ? "capture" : "render")
 
 template<typename T>
 int setup_wasapi_stream_one_side(cubeb_stream * stm,
                                  cubeb_stream_params * stream_params,
-                                 wchar_t const * devid,
+                                 cubeb_devid devid,
                                  EDataFlow direction,
                                  REFIID riid,
                                  IAudioClient ** audio_client,
                                  uint32_t * buffer_frame_count,
                                  HANDLE & event,
                                  T ** render_or_capture_client,
                                  cubeb_stream_params * mix_params)
 {
@@ -1424,22 +1409,24 @@ int setup_wasapi_stream_one_side(cubeb_s
   HRESULT hr;
 
   stm->stream_reset_lock.assert_current_thread_owns();
   bool try_again = false;
   // This loops until we find a device that works, or we've exhausted all
   // possibilities.
   do {
     if (devid) {
-      hr = get_endpoint(&device, devid);
+      std::unique_ptr<const wchar_t[]> id(utf8_to_wstr(reinterpret_cast<char*>(devid)));
+      hr = get_endpoint(&device, id.get());
       if (FAILED(hr)) {
         LOG("Could not get %s endpoint, error: %x\n", DIRECTION_NAME, hr);
         return CUBEB_ERROR;
       }
-    } else {
+    }
+    else {
       hr = get_default_endpoint(&device, direction);
       if (FAILED(hr)) {
         LOG("Could not get default %s endpoint, error: %x\n", DIRECTION_NAME, hr);
         return CUBEB_ERROR;
       }
     }
 
     /* Get a client. We will get all other interfaces we need from
@@ -1542,38 +1529,38 @@ int setup_wasapi_stream(cubeb_stream * s
   if (!com.ok()) {
     LOG("Failure to initialize COM.");
     return CUBEB_ERROR;
   }
 
   XASSERT((!stm->output_client || !stm->input_client) && "WASAPI stream already setup, close it first.");
 
   if (has_input(stm)) {
-    LOG("(%p) Setup capture: device=%p", stm, stm->input_device.get());
+    LOG("Setup capture: device=%x", (int)stm->input_device);
     rv = setup_wasapi_stream_one_side(stm,
                                       &stm->input_stream_params,
-                                      stm->input_device.get(),
+                                      stm->input_device,
                                       eCapture,
                                       __uuidof(IAudioCaptureClient),
                                       &stm->input_client,
                                       &stm->input_buffer_frame_count,
                                       stm->input_available_event,
                                       &stm->capture_client,
                                       &stm->input_mix_params);
     if (rv != CUBEB_OK) {
       LOG("Failure to open the input side.");
       return rv;
     }
   }
 
   if (has_output(stm)) {
-    LOG("(%p) Setup render: device=%p", stm, stm->output_device.get());
+    LOG("Setup render: device=%x", (int)stm->output_device);
     rv = setup_wasapi_stream_one_side(stm,
                                       &stm->output_stream_params,
-                                      stm->output_device.get(),
+                                      stm->output_device,
                                       eRender,
                                       __uuidof(IAudioRenderClient),
                                       &stm->output_client,
                                       &stm->output_buffer_frame_count,
                                       stm->refill_event,
                                       &stm->render_client,
                                       &stm->output_mix_params);
     if (rv != CUBEB_OK) {
@@ -1687,21 +1674,21 @@ wasapi_stream_init(cubeb * context, cube
 
   stm->context = context;
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   stm->draining = false;
   if (input_stream_params) {
     stm->input_stream_params = *input_stream_params;
-    stm->input_device = utf8_to_wstr(reinterpret_cast<char const *>(input_device));
+    stm->input_device = input_device;
   }
   if (output_stream_params) {
     stm->output_stream_params = *output_stream_params;
-    stm->output_device = utf8_to_wstr(reinterpret_cast<char const *>(output_device));
+    stm->output_device = output_device;
   }
 
   stm->latency = latency_frames;
   stm->volume = 1.0;
 
   // Placement new to call ctor.
   new (&stm->stream_reset_lock) owned_critical_section();
 
@@ -1785,26 +1772,17 @@ void close_wasapi_stream(cubeb_stream * 
   free(stm->mix_buffer);
   stm->mix_buffer = NULL;
 }
 
 void wasapi_stream_destroy(cubeb_stream * stm)
 {
   XASSERT(stm);
 
-  // Only free stm->emergency_bailout if we could not join the thread.
-  // If we could not join the thread, stm->emergency_bailout is true 
-  // and is still alive until the thread wakes up and exits cleanly.
-  if (stop_and_join_render_thread(stm)) {
-    delete stm->emergency_bailout.load();
-    stm->emergency_bailout = nullptr;
-  } else {
-    // If we're leaking, it must be that this is true.
-    assert(*(stm->emergency_bailout));
-  }
+  stop_and_join_render_thread(stm);
 
   unregister_notification_client(stm);
 
   SafeRelease(stm->reconfigure_event);
   SafeRelease(stm->refill_event);
   SafeRelease(stm->input_available_event);
 
   {
@@ -1863,18 +1841,16 @@ int stream_start_one_side(cubeb_stream *
 
 int wasapi_stream_start(cubeb_stream * stm)
 {
   XASSERT(stm && !stm->thread && !stm->shutdown_event);
   XASSERT(stm->output_client || stm->input_client);
 
   auto_lock lock(stm->stream_reset_lock);
 
-  stm->emergency_bailout = new std::atomic<bool>(false);
-
   if (stm->output_client) {
     int rv = stream_start_one_side(stm, OUTPUT);
     if (rv != CUBEB_OK) {
       return rv;
     }
   }
 
   if (stm->input_client) {
@@ -1924,22 +1900,17 @@ int wasapi_stream_stop(cubeb_stream * st
         return CUBEB_ERROR;
       }
     }
 
 
     stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
   }
 
-  if (stop_and_join_render_thread(stm)) {
-    if (stm->emergency_bailout.load()) {
-      delete stm->emergency_bailout.load();
-      stm->emergency_bailout = nullptr;
-    }
-  }
+  stop_and_join_render_thread(stm);
 
   return CUBEB_OK;
 }
 
 int wasapi_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   XASSERT(stm && position);
   auto_lock lock(stm->stream_reset_lock);
@@ -2006,39 +1977,43 @@ int wasapi_stream_set_volume(cubeb_strea
     return CUBEB_ERROR;
   }
 
   stm->volume = volume;
 
   return CUBEB_OK;
 }
 
-static char const *
+static char *
 wstr_to_utf8(LPCWSTR str)
 {
-  int size = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, nullptr, 0, NULL, NULL);
-  if (size <= 0) {
-    return nullptr;
+  char * ret = NULL;
+  int size;
+
+  size = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, 0, NULL, NULL);
+  if (size > 0) {
+    ret = static_cast<char *>(malloc(size));
+    ::WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL);
   }
 
-  char * ret = static_cast<char *>(malloc(size));
-  ::WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL);
   return ret;
 }
 
-static std::unique_ptr<wchar_t const []>
-utf8_to_wstr(char const * str)
+static std::unique_ptr<const wchar_t[]>
+utf8_to_wstr(char* str)
 {
-  int size = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
-  if (size <= 0) {
-    return nullptr;
+  std::unique_ptr<wchar_t[]> ret;
+  int size;
+
+  size = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
+  if (size > 0) {
+    ret.reset(new wchar_t[size]);
+    ::MultiByteToWideChar(CP_UTF8, 0, str, -1, ret.get(), size);
   }
 
-  std::unique_ptr<wchar_t []> ret(new wchar_t[size]);
-  ::MultiByteToWideChar(CP_UTF8, 0, str, -1, ret.get(), size);
   return std::move(ret);
 }
 
 static IMMDevice *
 wasapi_get_device_node(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
 {
   IMMDevice * ret = NULL;
   IDeviceTopology * devtopo = NULL;
@@ -2109,18 +2084,17 @@ wasapi_create_device(IMMDeviceEnumerator
   hr = dev->OpenPropertyStore(STGM_READ, &propstore);
   if (FAILED(hr)) goto done;
 
   hr = dev->GetState(&state);
   if (FAILED(hr)) goto done;
 
   ret = (cubeb_device_info *)calloc(1, sizeof(cubeb_device_info));
 
-  ret->device_id = wstr_to_utf8(device_id);
-  ret->devid = reinterpret_cast<cubeb_devid>(ret->device_id);
+  ret->devid = ret->device_id = wstr_to_utf8(device_id);
   hr = propstore->GetValue(PKEY_Device_FriendlyName, &propvar);
   if (SUCCEEDED(hr))
     ret->friendly_name = wstr_to_utf8(propvar.pwszVal);
 
   devnode = wasapi_get_device_node(enumerator, dev);
   if (devnode != NULL) {
     IPropertyStore * ps = NULL;
     hr = devnode->OpenPropertyStore(STGM_READ, &ps);
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -798,68 +798,68 @@ winmm_query_supported_formats(UINT devid
     *supfmt = (cubeb_device_fmt)(*supfmt | CUBEB_DEVICE_FMT_F32LE);
 
   return (*deffmt != 0) ? CUBEB_OK : CUBEB_ERROR;
 }
 
 static char *
 guid_to_cstr(LPGUID guid)
 {
-  char * ret = malloc(40);
+  char * ret = malloc(sizeof(char) * 40);
   if (!ret) {
     return NULL;
   }
-  _snprintf_s(ret, 40, _TRUNCATE,
+  _snprintf_s(ret, sizeof(char) * 40, _TRUNCATE,
       "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
       guid->Data1, guid->Data2, guid->Data3,
       guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
       guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
   return ret;
 }
 
 static cubeb_device_pref
 winmm_query_preferred_out_device(UINT devid)
 {
   DWORD mmpref = WAVE_MAPPER, compref = WAVE_MAPPER, status;
   cubeb_device_pref ret = CUBEB_DEVICE_PREF_NONE;
 
-  if (waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
+  if (waveOutMessage((HWAVEOUT)(size_t)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
         (DWORD_PTR)&mmpref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
       devid == mmpref)
     ret |= CUBEB_DEVICE_PREF_MULTIMEDIA | CUBEB_DEVICE_PREF_NOTIFICATION;
 
-  if (waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
+  if (waveOutMessage((HWAVEOUT)(size_t)WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
         (DWORD_PTR)&compref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
       devid == compref)
     ret |= CUBEB_DEVICE_PREF_VOICE;
 
   return ret;
 }
 
 static char *
 device_id_idx(UINT devid)
 {
-  char * ret = malloc(16);
+  char * ret = (char *)malloc(sizeof(char)*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)
 {
   cubeb_device_info * ret;
 
   ret = calloc(1, sizeof(cubeb_device_info));
   if (!ret) {
     return NULL;
   }
-  ret->devid = (cubeb_devid) devid;
+  ret->devid = (cubeb_devid)(size_t)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);
@@ -880,17 +880,17 @@ static cubeb_device_info *
 winmm_create_device_from_outcaps(LPWAVEOUTCAPSA caps, UINT devid)
 {
   cubeb_device_info * ret;
 
   ret = calloc(1, sizeof(cubeb_device_info));
   if (!ret) {
     return NULL;
   }
-  ret->devid = (cubeb_devid) devid;
+  ret->devid = (cubeb_devid)(size_t)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);
@@ -908,39 +908,39 @@ winmm_create_device_from_outcaps(LPWAVEO
 }
 
 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;
 
-  if (waveInMessage((HWAVEIN) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
+  if (waveInMessage((HWAVEIN)(size_t)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET,
         (DWORD_PTR)&mmpref, (DWORD_PTR)&status) == MMSYSERR_NOERROR &&
       devid == mmpref)
     ret |= CUBEB_DEVICE_PREF_MULTIMEDIA | CUBEB_DEVICE_PREF_NOTIFICATION;
 
-  if (waveInMessage((HWAVEIN) WAVE_MAPPER, DRVM_MAPPER_CONSOLEVOICECOM_GET,
+  if (waveInMessage((HWAVEIN)(size_t)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)
 {
   cubeb_device_info * ret;
 
   ret = calloc(1, sizeof(cubeb_device_info));
   if (!ret) {
     return NULL;
   }
-  ret->devid = (cubeb_devid) devid;
+  ret->devid = (cubeb_devid)(size_t)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);
@@ -961,17 +961,17 @@ static cubeb_device_info *
 winmm_create_device_from_incaps(LPWAVEINCAPSA caps, UINT devid)
 {
   cubeb_device_info * ret;
 
   ret = calloc(1, sizeof(cubeb_device_info));
   if (!ret) {
     return NULL;
   }
-  ret->devid = (cubeb_devid) devid;
+  ret->devid = (cubeb_devid)(size_t)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);
rename from media/libcubeb/gtest/common.h
rename to media/libcubeb/tests/common.h
--- a/media/libcubeb/gtest/common.h
+++ b/media/libcubeb/tests/common.h
@@ -1,16 +1,14 @@
 /*
  * Copyright © 2013 Sebastien Alaiwan
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
-#if !defined(TEST_COMMON)
-#define TEST_COMMON
 
 #if defined( _WIN32)
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #endif
 #include <windows.h>
 #else
 #include <unistd.h>
@@ -56,9 +54,8 @@ int has_available_input_device(cubeb * c
     fprintf(stderr, "there are input devices, but they are not "
         "available, skipping\n");
     return 0;
   }
 
   return 1;
 }
 
-#endif /* TEST_COMMON */
rename from media/libcubeb/gtest/moz.build
rename to media/libcubeb/tests/moz.build
--- a/media/libcubeb/gtest/moz.build
+++ b/media/libcubeb/tests/moz.build
@@ -1,32 +1,34 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-UNIFIED_SOURCES += [
-#  'test_duplex.cpp', # DISABLED: See bug 1314514.
-#  'test_record.cpp', # DISABLED: See bug 1314514.
-  'test_tone.cpp',
-  'test_utils.cpp'
-]
+DEFINES['CUBEB_GECKO_BUILD'] = True
+
+GeckoCppUnitTests([
+  'test_duplex',
+  'test_record',
+  'test_tone',
+  'test_utils'
+])
 
 if CONFIG['MOZ_PULSEAUDIO'] or CONFIG['OS_TARGET'] in ('Darwin', 'WINNT', 'Android'):
-  UNIFIED_SOURCES += [
-    'test_resampler.cpp',
-  ]
+  GeckoCppUnitTests([
+    'test_resampler',
+  ])
 
 if CONFIG['OS_TARGET'] != 'Android':
-  UNIFIED_SOURCES += [
-    'test_audio.cpp',
-    'test_latency.cpp',
-    'test_sanity.cpp'
-  ]
+  GeckoCppUnitTests([
+    'test_audio',
+    'test_latency',
+    'test_sanity'
+  ])
 
 LOCAL_INCLUDES += [
     '../include',
     '../src'
 ]
 
 USE_LIBS += [
     'cubeb',
@@ -71,10 +73,8 @@ elif CONFIG['OS_TARGET'] == 'OpenBSD':
         'sndio',
     ]
 else:
     OS_LIBS += CONFIG['MOZ_ALSA_LIBS']
     OS_LIBS += CONFIG['MOZ_PULSEAUDIO_LIBS']
 
 if CONFIG['GNU_CXX']:
     CXXFLAGS += ['-Wno-error=shadow']
-
-FINAL_LIBRARY = 'xul-gtest'
rename from media/libcubeb/gtest/test_audio.cpp
rename to media/libcubeb/tests/test_audio.cpp
--- a/media/libcubeb/gtest/test_audio.cpp
+++ b/media/libcubeb/tests/test_audio.cpp
@@ -2,26 +2,31 @@
  * Copyright © 2013 Sebastien Alaiwan <sebastien.alaiwan@gmail.com>
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 /* libcubeb api/function exhaustive test. Plays a series of tones in different
  * conditions. */
-#include "gtest/gtest.h"
-#if !defined(_XOPEN_SOURCE)
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #define _XOPEN_SOURCE 600
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <assert.h>
 #include <string.h>
+
 #include "cubeb/cubeb.h"
 #include "common.h"
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
 
 #define MAX_NUM_CHANNELS 32
 
 #if !defined(M_PI)
 #define M_PI 3.14159265358979323846
 #endif
 
 #define NELEMS(x) ((int) (sizeof(x) / sizeof(x[0])))
@@ -89,17 +94,17 @@ void synth_run_16bit(synth_state* synth,
 
 long data_cb_short(cubeb_stream * /*stream*/, void * user, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
 {
   synth_state *synth = (synth_state *)user;
   synth_run_16bit(synth, (short*)outputbuffer, nframes);
   return nframes;
 }
 
-void state_cb_audio(cubeb_stream * /*stream*/, void * /*user*/, cubeb_state /*state*/)
+void state_cb(cubeb_stream * /*stream*/, void * /*user*/, cubeb_state /*state*/)
 {
 }
 
 /* Our android backends don't support float, only int16. */
 int supports_float32(const char* backend_id)
 {
   return (strcmp(backend_id, "opensl") != 0 &&
           strcmp(backend_id, "audiotrack") != 0);
@@ -151,17 +156,17 @@ int run_test(int num_channels, int sampl
 
   synth = synth_create(params.channels, params.rate);
   if (synth == NULL) {
     fprintf(stderr, "Out of memory\n");
     goto cleanup;
   }
 
   r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, &params,
-                        4096, is_float ? data_cb_float : data_cb_short, state_cb_audio, synth);
+                        4096, is_float ? data_cb_float : data_cb_short, state_cb, synth);
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
     goto cleanup;
   }
 
   cubeb_stream_start(stream);
   delay(200);
   cubeb_stream_stop(stream);
@@ -204,17 +209,17 @@ int run_panning_volume_test(int is_float
   synth = synth_create(params.channels, params.rate);
   if (synth == NULL) {
     fprintf(stderr, "Out of memory\n");
     goto cleanup;
   }
 
   r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, &params,
                         4096, is_float ? data_cb_float : data_cb_short,
-                        state_cb_audio, synth);
+                        state_cb, synth);
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb stream: %d\n", r);
     goto cleanup;
   }
 
   fprintf(stderr, "Testing: volume\n");
   for(int i=0;i <= 4; ++i)
   {
@@ -242,27 +247,17 @@ int run_panning_volume_test(int is_float
 cleanup:
   cubeb_stream_destroy(stream);
   cubeb_destroy(ctx);
   synth_destroy(synth);
 
   return r;
 }
 
-TEST(cubeb, run_panning_volume_test_short)
-{
-  ASSERT_EQ(run_panning_volume_test(0), CUBEB_OK);
-}
-
-TEST(cubeb, run_panning_volume_test_float)
-{
-  ASSERT_EQ(run_panning_volume_test(1), CUBEB_OK);
-}
-
-TEST(cubeb, run_channel_rate_test)
+void run_channel_rate_test()
 {
   int channel_values[] = {
     1,
     2,
     3,
     4,
     6,
   };
@@ -271,16 +266,29 @@ TEST(cubeb, run_channel_rate_test)
     16000,
     24000,
     44100,
     48000,
   };
 
   for(int j = 0; j < NELEMS(channel_values); ++j) {
     for(int i = 0; i < NELEMS(freq_values); ++i) {
-      ASSERT_TRUE(channel_values[j] < MAX_NUM_CHANNELS);
+      assert(channel_values[j] < MAX_NUM_CHANNELS);
       fprintf(stderr, "--------------------------\n");
-      ASSERT_EQ(run_test(channel_values[j], freq_values[i], 0), CUBEB_OK);
-      ASSERT_EQ(run_test(channel_values[j], freq_values[i], 1), CUBEB_OK);
+      assert(run_test(channel_values[j], freq_values[i], 0) == CUBEB_OK);
+      assert(run_test(channel_values[j], freq_values[i], 1) == CUBEB_OK);
     }
   }
 }
 
+
+int main(int /*argc*/, char * /*argv*/[])
+{
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_audio");
+#endif
+
+  assert(run_panning_volume_test(0) == CUBEB_OK);
+  assert(run_panning_volume_test(1) == CUBEB_OK);
+  run_channel_rate_test();
+
+  return CUBEB_OK;
+}
rename from media/libcubeb/gtest/test_devices.cpp
rename to media/libcubeb/tests/test_devices.cpp
--- a/media/libcubeb/gtest/test_devices.cpp
+++ b/media/libcubeb/tests/test_devices.cpp
@@ -2,22 +2,27 @@
  * Copyright © 2015 Haakon Sporsheim <haakon.sporsheim@telenordigital.com>
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 /* libcubeb enumerate device test/example.
  * Prints out a list of devices enumerated. */
-#include "gtest/gtest.h"
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+
 #include "cubeb/cubeb.h"
 
+
 static void
 print_device_info(cubeb_device_info * info, FILE * f)
 {
   char devfmts[64] = "";
   const char * devtype, * devstate, * devdeffmt;
 
   switch (info->type) {
     case CUBEB_DEVICE_TYPE_INPUT:
@@ -79,57 +84,52 @@ print_device_info(cubeb_device_info * in
       "\tName:    \"%s\"\n"
       "\tGroup:   \"%s\"\n"
       "\tVendor:  \"%s\"\n"
       "\tType:    %s\n"
       "\tState:   %s\n"
       "\tCh:      %u\n"
       "\tFormat:  %s (0x%x) (default: %s)\n"
       "\tRate:    %u - %u (default: %u)\n"
-      "\tLatency: lo %u frames, hi %u frames\n",
+      "\tLatency: lo %ums, hi %ums\n",
       info->device_id, info->preferred ? " (PREFERRED)" : "",
       info->friendly_name, info->group_id, info->vendor_name,
       devtype, devstate, info->max_channels,
-      (devfmts[0] == '\0') ? devfmts : devfmts + 1,
+      (devfmts[0] == ' ') ? &devfmts[1] : devfmts,
       (unsigned int)info->format, devdeffmt,
       info->min_rate, info->max_rate, info->default_rate,
-      info->latency_lo, info->latency_hi);
+      info->latency_lo_ms, info->latency_hi_ms);
 }
 
 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);
 }
 
-TEST(cubeb, enumerate_devices)
+static int
+run_enumerate_devices(void)
 {
-  int r;
+  int r = CUBEB_OK;
   cubeb * ctx = NULL;
   cubeb_device_collection * collection = NULL;
 
   r = cubeb_init(&ctx, "Cubeb audio test");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   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;
-    goto cleanup;
-  }
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error enumerating devices %d\n", r);
     goto cleanup;
   }
 
   fprintf(stdout, "Found %u input devices\n", collection->count);
   print_device_collection(collection, stdout);
   cubeb_device_collection_destroy(collection);
@@ -144,11 +144,19 @@ TEST(cubeb, enumerate_devices)
   }
 
   fprintf(stdout, "Found %u output devices\n", collection->count);
   print_device_collection(collection, stdout);
   cubeb_device_collection_destroy(collection);
 
 cleanup:
   cubeb_destroy(ctx);
-  ASSERT_EQ(r, CUBEB_OK);
+  return r;
 }
 
+int main(int argc, char *argv[])
+{
+  int ret;
+
+  ret = run_enumerate_devices();
+
+  return ret;
+}
rename from media/libcubeb/gtest/test_duplex.cpp
rename to media/libcubeb/tests/test_duplex.cpp
--- a/media/libcubeb/gtest/test_duplex.cpp
+++ b/media/libcubeb/tests/test_duplex.cpp
@@ -2,43 +2,50 @@
  * Copyright © 2016 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 /* libcubeb api/function test. Loops input back to output and check audio
  * is flowing. */
-#include "gtest/gtest.h"
-#if !defined(_XOPEN_SOURCE)
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #define _XOPEN_SOURCE 600
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <assert.h>
+
 #include "cubeb/cubeb.h"
 #include "common.h"
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
 
 #define SAMPLE_FREQUENCY 48000
 #if (defined(_WIN32) || defined(__WIN32__))
 #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
 #define SILENT_SAMPLE 0.0f
 #else
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #define SILENT_SAMPLE 0
 #endif
 
-struct user_state_duplex
+struct user_state
 {
   bool seen_noise;
 };
 
-long data_cb_duplex(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
+
+
+long data_cb(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
 {
-  user_state_duplex * u = reinterpret_cast<user_state_duplex*>(user);
+  user_state * u = reinterpret_cast<user_state*>(user);
 #if (defined(_WIN32) || defined(__WIN32__))
   float *ib = (float *)inputbuffer;
   float *ob = (float *)outputbuffer;
 #else
   short *ib = (short *)inputbuffer;
   short *ob = (short *)outputbuffer;
 #endif
   bool seen_noise = false;
@@ -58,17 +65,17 @@ long data_cb_duplex(cubeb_stream * strea
     output_index += 2;
   }
 
   u->seen_noise |= seen_noise;
 
   return nframes;
 }
 
-void state_cb_duplex(cubeb_stream * stream, void * /*user*/, cubeb_state state)
+void state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
 {
   if (stream == NULL)
     return;
 
   switch (state) {
   case CUBEB_STATE_STARTED:
     printf("stream started\n"); break;
   case CUBEB_STATE_STOPPED:
@@ -77,62 +84,68 @@ void state_cb_duplex(cubeb_stream * stre
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-TEST(cubeb, duplex)
+int main(int /*argc*/, char * /*argv*/[])
 {
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_duplex");
+#endif
+
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params input_params;
   cubeb_stream_params output_params;
   int r;
-  user_state_duplex stream_state = { false };
+  user_state stream_state = { false };
   uint32_t latency_frames = 0;
 
   r = cubeb_init(&ctx, "Cubeb duplex example");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   /* This test needs an available input device, skip it if this host does not
    * have one. */
   if (!has_available_input_device(ctx)) {
-    return;
+    return 0;
   }
 
   /* typical user-case: mono input, stereo output, low latency. */
   input_params.format = STREAM_FORMAT;
   input_params.rate = 48000;
   input_params.channels = 1;
   output_params.format = STREAM_FORMAT;
   output_params.rate = 48000;
   output_params.channels = 2;
 
   r = cubeb_get_min_latency(ctx, output_params, &latency_frames);
 
   if (r != CUBEB_OK) {
     fprintf(stderr, "Could not get minimal latency\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb duplex",
                         NULL, &input_params, NULL, &output_params,
-                        latency_frames, data_cb_duplex, state_cb_duplex, &stream_state);
+                        latency_frames, data_cb, state_cb, &stream_state);
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb stream\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   cubeb_stream_start(stream);
   delay(500);
   cubeb_stream_stop(stream);
 
   cubeb_stream_destroy(stream);
   cubeb_destroy(ctx);
 
-  ASSERT_TRUE(stream_state.seen_noise);
+  assert(stream_state.seen_noise);
+
+  return CUBEB_OK;
 }
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/tests/test_latency.cpp
@@ -0,0 +1,60 @@
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+#include <stdlib.h>
+#include "cubeb/cubeb.h"
+#include <assert.h>
+#include <stdio.h>
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
+
+#define LOG(msg) fprintf(stderr, "%s\n", msg);
+
+int main(int /*argc*/, char * /*argv*/[])
+{
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_latency");
+#endif
+
+  cubeb * ctx = NULL;
+  int r;
+  uint32_t max_channels;
+  uint32_t preferred_rate;
+  uint32_t latency_frames;
+
+  LOG("latency_test start");
+  r = cubeb_init(&ctx, "Cubeb audio test");
+  assert(r == CUBEB_OK && "Cubeb init failed.");
+  LOG("cubeb_init ok");
+
+  r = cubeb_get_max_channel_count(ctx, &max_channels);
+  assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
+  if (r == CUBEB_OK) {
+    assert(max_channels > 0 && "Invalid max channel count.");
+    LOG("cubeb_get_max_channel_count ok");
+  }
+
+  r = cubeb_get_preferred_sample_rate(ctx, &preferred_rate);
+  assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
+  if (r == CUBEB_OK) {
+    assert(preferred_rate > 0 && "Invalid preferred sample rate.");
+    LOG("cubeb_get_preferred_sample_rate ok");
+  }
+
+  cubeb_stream_params params = {
+    CUBEB_SAMPLE_FLOAT32NE,
+    preferred_rate,
+    max_channels
+  };
+  r = cubeb_get_min_latency(ctx, params, &latency_frames);
+  assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
+  if (r == CUBEB_OK) {
+    assert(latency_frames > 0 && "Invalid minimal latency.");
+    LOG("cubeb_get_min_latency ok");
+  }
+
+  cubeb_destroy(ctx);
+  LOG("cubeb_destroy ok");
+  return EXIT_SUCCESS;
+}
rename from media/libcubeb/gtest/test_record.cpp
rename to media/libcubeb/tests/test_record.cpp
--- a/media/libcubeb/gtest/test_record.cpp
+++ b/media/libcubeb/tests/test_record.cpp
@@ -1,41 +1,46 @@
 /*
  * Copyright © 2016 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 /* libcubeb api/function test. Record the mic and check there is sound. */
-#include "gtest/gtest.h"
-#if !defined(_XOPEN_SOURCE)
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #define _XOPEN_SOURCE 600
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <assert.h>
+
 #include "cubeb/cubeb.h"
 #include "common.h"
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
 
 #define SAMPLE_FREQUENCY 48000
 #if (defined(_WIN32) || defined(__WIN32__))
 #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
 #else
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #endif
 
-struct user_state_record
+struct user_state
 {
   bool seen_noise;
 };
 
-long data_cb_record(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
+long data_cb(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
 {
-  user_state_record * u = reinterpret_cast<user_state_record*>(user);
+  user_state * u = reinterpret_cast<user_state*>(user);
 #if STREAM_FORMAT != CUBEB_SAMPLE_FLOAT32LE
   short *b = (short *)inputbuffer;
 #else
   float *b = (float *)inputbuffer;
 #endif
 
   if (stream == NULL  || inputbuffer == NULL || outputbuffer != NULL) {
     return CUBEB_ERROR;
@@ -48,17 +53,17 @@ long data_cb_record(cubeb_stream * strea
     }
   }
 
   u->seen_noise |= seen_noise;
 
   return nframes;
 }
 
-void state_cb_record(cubeb_stream * stream, void * /*user*/, cubeb_state state)
+void state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
 {
   if (stream == NULL)
     return;
 
   switch (state) {
   case CUBEB_STATE_STARTED:
     printf("stream started\n"); break;
   case CUBEB_STATE_STOPPED:
@@ -67,48 +72,54 @@ void state_cb_record(cubeb_stream * stre
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-TEST(cubeb, record)
+int main(int /*argc*/, char * /*argv*/[])
 {
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_record");
+#endif
+
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
   int r;
-  user_state_record stream_state = { false };
+  user_state stream_state = { false };
 
   r = cubeb_init(&ctx, "Cubeb record example");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   /* This test needs an available input device, skip it if this host does not
    * have one. */
   if (!has_available_input_device(ctx)) {
-    return;
+    return 0;
   }
 
   params.format = STREAM_FORMAT;
   params.rate = SAMPLE_FREQUENCY;
   params.channels = 1;
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, &params, NULL, nullptr,
-                        4096, data_cb_record, state_cb_record, &stream_state);
+                        4096, data_cb, state_cb, &stream_state);
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb stream\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   cubeb_stream_start(stream);
   delay(500);
   cubeb_stream_stop(stream);
 
   cubeb_stream_destroy(stream);
   cubeb_destroy(ctx);
 
-  ASSERT_TRUE(stream_state.seen_noise);
+  assert(stream_state.seen_noise);
+
+  return CUBEB_OK;
 }
rename from media/libcubeb/gtest/test_resampler.cpp
rename to media/libcubeb/tests/test_resampler.cpp
--- a/media/libcubeb/gtest/test_resampler.cpp
+++ b/media/libcubeb/tests/test_resampler.cpp
@@ -2,18 +2,22 @@
  * Copyright © 2016 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 #ifndef NOMINMAX
 #define NOMINMAX
 #endif // NOMINMAX
-#include "gtest/gtest.h"
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #include "cubeb_resampler_internal.h"
+#include <assert.h>
 #include <stdio.h>
 #include <algorithm>
 #include <iostream>
 
 /* Windows cmath USE_MATH_DEFINE thing... */
 const float PI = 3.14159265359f;
 
 /* Testing all sample rates is very long, so if THOROUGH_TESTING is not defined,
@@ -145,17 +149,17 @@ void test_delay_lines(uint32_t delay_fra
     delay.written(to_pop / channels);
     output.push_silence(to_pop);
     delay.output(output.data() + output_offset, to_pop / channels);
     output_offset += to_pop;
   }
 
   // Check the diracs have been shifted by `delay_frames` frames.
   for (uint32_t i = 0; i < output.length() - delay_frames * channels + 1; i+=100) {
-    ASSERT_EQ(output.data()[i + channel + delay_frames * channels], 0.5);
+    assert(output.data()[i + channel + delay_frames * channels] == 0.5);
     channel = (channel + 1) % channels;
   }
 
   dump("output.raw", output.data(), output.length());
 }
 /**
  * This takes sine waves with a certain `channels` count, `source_rate`, and
  * resample them, by chunk of `chunk_duration` milliseconds, to `target_rate`.
@@ -223,17 +227,17 @@ void test_resampler_one_way(uint32_t cha
   bool fuzzy_equal = true;
   for (uint32_t i = resampler.latency() + 1; i < expected.length(); i++) {
     float diff = fabs(expected.data()[i] - destination.data()[i]);
     if (diff > epsilon<T>(resampling_ratio)) {
       fprintf(stderr, "divergence at %d: %f %f (delta %f)\n", i, expected.data()[i], destination.data()[i], diff);
       fuzzy_equal = false;
     }
   }
-  ASSERT_TRUE(fuzzy_equal);
+  assert(fuzzy_equal);
 }
 
 template<typename T>
 cubeb_sample_format cubeb_format();
 
 template<>
 cubeb_sample_format cubeb_format<float>()
 {
@@ -274,17 +278,17 @@ uint32_t fill_with_sine(float * buf, uin
     float  p = initial_phase++ / static_cast<float>(rate);
     for (uint32_t j = 0; j < channels; j++) {
       buf[offset++] = 0.5 * sin(440. * 2 * PI * p);
     }
   }
   return initial_phase;
 }
 
-long data_cb_resampler(cubeb_stream * /*stm*/, void * user_ptr,
+long data_cb(cubeb_stream * /*stm*/, void * user_ptr,
              const void * input_buffer, void * output_buffer, long frame_count)
 {
   osc_state * state = reinterpret_cast<osc_state*>(user_ptr);
   const float * in = reinterpret_cast<const float*>(input_buffer);
   float * out = reinterpret_cast<float*>(output_buffer);
 
 
   state->input.push(in, frame_count * state->input_channels);
@@ -332,17 +336,17 @@ void test_resampler_duplex(uint32_t inpu
   state.output_channels = output_params.channels = output_channels;
   input_params.rate = input_rate;
   state.output_rate = output_params.rate = output_rate;
   state.target_rate = target_rate;
   long got;
 
   cubeb_resampler * resampler =
     cubeb_resampler_create((cubeb_stream*)nullptr, &input_params, &output_params, target_rate,
-                           data_cb_resampler, (void*)&state, CUBEB_RESAMPLER_QUALITY_VOIP);
+                           data_cb, (void*)&state, CUBEB_RESAMPLER_QUALITY_VOIP);
 
   long latency = cubeb_resampler_latency(resampler);
 
   const uint32_t duration_s = 2;
   int32_t duration_frames = duration_s * target_rate;
   uint32_t input_array_frame_count = ceil(chunk_duration * input_rate / 1000) + ceilf(static_cast<float>(input_rate) / target_rate) * 2;
   uint32_t output_array_frame_count = chunk_duration * output_rate / 1000;
   auto_array<float> input_buffer(input_channels * input_array_frame_count);
@@ -388,46 +392,44 @@ void test_resampler_duplex(uint32_t inpu
     state.output.push(output_buffer.data(), got * state.output_channels);
   }
 
   dump("input_expected.raw", expected_resampled_input.data(), expected_resampled_input.length());
   dump("output_expected.raw", expected_resampled_output.data(), expected_resampled_output.length());
   dump("input.raw", state.input.data(), state.input.length());
   dump("output.raw", state.output.data(), state.output.length());
 
-  ASSERT_TRUE(array_fuzzy_equal(state.input, expected_resampled_input, epsilon<T>(input_rate/target_rate)));
-  ASSERT_TRUE(array_fuzzy_equal(state.output, expected_resampled_output, epsilon<T>(output_rate/target_rate)));
+  assert(array_fuzzy_equal(state.input, expected_resampled_input, epsilon<T>(input_rate/target_rate)));
+  assert(array_fuzzy_equal(state.output, expected_resampled_output, epsilon<T>(output_rate/target_rate)));
 
   cubeb_resampler_destroy(resampler);
 }
 
 #define array_size(x) (sizeof(x) / sizeof(x[0]))
 
-TEST(cubeb, resampler_one_way)
+void test_resamplers_one_way()
 {
   /* Test one way resamplers */
   for (uint32_t channels = 1; channels <= max_channels; channels++) {
     for (uint32_t source_rate = 0; source_rate < array_size(sample_rates); source_rate++) {
       for (uint32_t dest_rate = 0; dest_rate < array_size(sample_rates); dest_rate++) {
         for (uint32_t chunk_duration = min_chunks; chunk_duration < max_chunks; chunk_duration+=chunk_increment) {
           printf("one_way: channels: %d, source_rate: %d, dest_rate: %d, chunk_duration: %d\n",
                   channels, sample_rates[source_rate], sample_rates[dest_rate], chunk_duration);
           test_resampler_one_way<float>(channels, sample_rates[source_rate],
                                         sample_rates[dest_rate], chunk_duration);
         }
       }
     }
   }
 }
 
-// This is disabled because the latency estimation in the resampler code is
-// slightly off so we can generate expected vectors.
-// See https://github.com/kinetiknz/cubeb/issues/93
-TEST(cubeb, DISABLED_resampler_duplex)
+void test_resamplers_duplex()
 {
+  /* Test duplex resamplers */
   for (uint32_t input_channels = 1; input_channels <= max_channels; input_channels++) {
     for (uint32_t output_channels = 1; output_channels <= max_channels; output_channels++) {
       for (uint32_t source_rate_input = 0; source_rate_input < array_size(sample_rates); source_rate_input++) {
         for (uint32_t source_rate_output = 0; source_rate_output < array_size(sample_rates); source_rate_output++) {
           for (uint32_t dest_rate = 0; dest_rate < array_size(sample_rates); dest_rate++) {
             for (uint32_t chunk_duration = min_chunks; chunk_duration < max_chunks; chunk_duration+=chunk_increment) {
               printf("input channels:%d output_channels:%d input_rate:%d "
                      "output_rate:%d target_rate:%d chunk_ms:%d\n",
@@ -444,39 +446,39 @@ TEST(cubeb, DISABLED_resampler_duplex)
             }
           }
         }
       }
     }
   }
 }
 
-TEST(cubeb, resampler_delay_line)
+void test_delay_line()
 {
   for (uint32_t channel = 1; channel <= 2; channel++) {
     for (uint32_t delay_frames = 4; delay_frames <= 40; delay_frames+=chunk_increment) {
       for (uint32_t chunk_size = 10; chunk_size <= 30; chunk_size++) {
        printf("channel: %d, delay_frames: %d, chunk_size: %d\n",
               channel, delay_frames, chunk_size);
         test_delay_lines(delay_frames, channel, chunk_size);
       }
     }
   }
 }
 
 long test_output_only_noop_data_cb(cubeb_stream * /*stm*/, void * /*user_ptr*/,
                                    const void * input_buffer,
                                    void * output_buffer, long frame_count)
 {
-  EXPECT_TRUE(output_buffer);
-  EXPECT_TRUE(!input_buffer);
+  assert(output_buffer);
+  assert(!input_buffer);
   return frame_count;
 }
 
-TEST(cubeb, resampler_output_only_noop)
+void test_output_only_noop()
 {
   cubeb_stream_params output_params;
   int target_rate;
 
   output_params.rate = 44100;
   output_params.channels = 1;
   output_params.format = CUBEB_SAMPLE_FLOAT32NE;
   target_rate = output_params.rate;
@@ -488,31 +490,31 @@ TEST(cubeb, resampler_output_only_noop)
 
   const long out_frames = 128;
   float out_buffer[out_frames];
   long got;
 
   got = cubeb_resampler_fill(resampler, nullptr, nullptr,
                              out_buffer, out_frames);
 
-  ASSERT_EQ(got, out_frames);
+  assert(got == out_frames);
 
   cubeb_resampler_destroy(resampler);
 }
 
 long test_drain_data_cb(cubeb_stream * /*stm*/, void * /*user_ptr*/,
                         const void * input_buffer,
                         void * output_buffer, long frame_count)
 {
-  EXPECT_TRUE(output_buffer);
-  EXPECT_TRUE(!input_buffer);
+  assert(output_buffer);
+  assert(!input_buffer);
   return frame_count - 10;
 }
 
-TEST(cubeb, resampler_drain)
+void test_resampler_drain()
 {
   cubeb_stream_params output_params;
   int target_rate;
 
   output_params.rate = 44100;
   output_params.channels = 1;
   output_params.format = CUBEB_SAMPLE_FLOAT32NE;
   target_rate = 48000;
@@ -528,13 +530,25 @@ TEST(cubeb, resampler_drain)
 
   do {
     got = cubeb_resampler_fill(resampler, nullptr, nullptr,
                                out_buffer, out_frames);
   } while (got == out_frames);
 
   /* If the above is not an infinite loop, the drain was a success, just mark
    * this test as such. */
-  ASSERT_TRUE(true);
+  assert(true);
 
   cubeb_resampler_destroy(resampler);
 }
 
+int main()
+{
+  test_resamplers_one_way();
+  test_delay_line();
+  // This is disabled because the latency estimation in the resampler code is
+  // slightly off so we can generate expected vectors.
+  // test_resamplers_duplex();
+  test_output_only_noop();
+  test_resampler_drain();
+
+  return 0;
+}
rename from media/libcubeb/gtest/test_sanity.cpp
rename to media/libcubeb/tests/test_sanity.cpp
--- a/media/libcubeb/gtest/test_sanity.cpp
+++ b/media/libcubeb/tests/test_sanity.cpp
@@ -1,24 +1,30 @@
 /*
  * Copyright © 2011 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
-#include "gtest/gtest.h"
-#if !defined(_XOPEN_SOURCE)
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #define _XOPEN_SOURCE 600
-#endif
 #include "cubeb/cubeb.h"
-#include <atomic>
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
 #include "common.h"
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
+
+#define BEGIN_TEST fprintf(stderr, "START %s\n", __func__)
+#define END_TEST fprintf(stderr, "END %s\n", __func__)
 
 #define STREAM_RATE 44100
 #define STREAM_LATENCY 100 * STREAM_RATE / 1000
 #define STREAM_CHANNELS 1
 #if (defined(_WIN32) || defined(__WIN32__))
 #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
 #else
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
@@ -26,16 +32,580 @@
 
 template<typename T, size_t N>
 constexpr size_t
 ARRAY_LENGTH(T(&)[N])
 {
   return N;
 }
 
+static int dummy;
+static uint64_t total_frames_written;
+static int delay_callback;
+
+static long
+test_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
+{
+  assert(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
+#if (defined(_WIN32) || defined(__WIN32__))
+  memset(outputbuffer, 0, nframes * sizeof(float));
+#else
+  memset(outputbuffer, 0, nframes * sizeof(short));
+#endif
+
+  total_frames_written += nframes;
+  if (delay_callback) {
+    delay(10);
+  }
+  return nframes;
+}
+
+void
+test_state_callback(cubeb_stream * /*stm*/, void * /*user_ptr*/, cubeb_state /*state*/)
+{
+}
+
+static void
+test_init_destroy_context(void)
+{
+  int r;
+  cubeb * ctx;
+  char const* backend_id;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+
+  backend_id = cubeb_get_backend_id(ctx);
+  assert(backend_id);
+
+  fprintf(stderr, "Backend: %s\n", backend_id);
+
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_init_destroy_multiple_contexts(void)
+{
+  size_t i;
+  int r;
+  cubeb * ctx[4];
+  int order[4] = {2, 0, 3, 1};
+  assert(ARRAY_LENGTH(ctx) == ARRAY_LENGTH(order));
+
+  BEGIN_TEST;
+
+  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
+    r = cubeb_init(&ctx[i], NULL);
+    assert(r == 0 && ctx[i]);
+  }
+
+  /* destroy in a different order */
+  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
+    cubeb_destroy(ctx[order[i]]);
+  }
+
+  END_TEST;
+}
+
+static void
+test_context_variables(void)
+{
+  int r;
+  cubeb * ctx;
+  uint32_t value;
+  cubeb_stream_params params;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_context_variables");
+  assert(r == 0 && ctx);
+
+  params.channels = STREAM_CHANNELS;
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+#if defined(__ANDROID__)
+  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
+#endif
+  r = cubeb_get_min_latency(ctx, params, &value);
+  assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
+  if (r == CUBEB_OK) {
+    assert(value > 0);
+  }
+
+  r = cubeb_get_preferred_sample_rate(ctx, &value);
+  assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
+  if (r == CUBEB_OK) {
+    assert(value > 0);
+  }
+
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_init_destroy_stream(void)
+{
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#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(r == 0 && stream);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_init_destroy_multiple_streams(void)
+{
+  size_t i;
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream[8];
+  cubeb_stream_params params;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#if defined(__ANDROID__)
+  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
+#endif
+
+  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+    r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
+                          test_data_callback, test_state_callback, &dummy);
+    assert(r == 0);
+    assert(stream[i]);
+  }
+
+  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+    cubeb_stream_destroy(stream[i]);
+  }
+
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_configure_stream(void)
+{
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = 2; // panning
+#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(r == 0 && stream);
+
+  r = cubeb_stream_set_volume(stream, 1.0f);
+  assert(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);
+
+  r = cubeb_stream_set_panning(stream, 0.0f);
+  assert(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+  END_TEST;
+}
+
+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;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#if defined(__ANDROID__)
+  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
+#endif
+
+  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+    r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
+                          test_data_callback, test_state_callback, &dummy);
+    assert(r == 0);
+    assert(stream[i]);
+    if (early) {
+      r = cubeb_stream_start(stream[i]);
+      assert(r == 0);
+    }
+  }
+
+
+  if (!early) {
+    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+      r = cubeb_stream_start(stream[i]);
+      assert(r == 0);
+    }
+  }
+
+  if (delay_ms) {
+    delay(delay_ms);
+  }
+
+  if (!early) {
+    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+      r = cubeb_stream_stop(stream[i]);
+      assert(r == 0);
+    }
+  }
+
+  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
+    if (early) {
+      r = cubeb_stream_stop(stream[i]);
+      assert(r == 0);
+    }
+    cubeb_stream_destroy(stream[i]);
+  }
+
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_init_destroy_multiple_contexts_and_streams(void)
+{
+  size_t i, j;
+  int r;
+  cubeb * ctx[2];
+  cubeb_stream * stream[8];
+  cubeb_stream_params params;
+  size_t streams_per_ctx = ARRAY_LENGTH(stream) / ARRAY_LENGTH(ctx);
+  assert(ARRAY_LENGTH(ctx) * streams_per_ctx == ARRAY_LENGTH(stream));
+
+  BEGIN_TEST;
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#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");
+    assert(r == 0 && ctx[i]);
+
+    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(r == 0);
+      assert(stream[i * streams_per_ctx + j]);
+    }
+  }
+
+  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
+    for (j = 0; j < streams_per_ctx; ++j) {
+      cubeb_stream_destroy(stream[i * streams_per_ctx + j]);
+    }
+    cubeb_destroy(ctx[i]);
+  }
+
+  END_TEST;
+}
+
+static void
+test_basic_stream_operations(void)
+{
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+  uint64_t position;
+
+  BEGIN_TEST;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#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(r == 0 && stream);
+
+  /* position and volume before stream has started */
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0 && position == 0);
+
+  r = cubeb_stream_start(stream);
+  assert(r == 0);
+
+  /* position and volume after while stream running */
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+
+  r = cubeb_stream_stop(stream);
+  assert(r == 0);
+
+  /* position and volume after stream has stopped */
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static void
+test_stream_position(void)
+{
+  size_t i;
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+  uint64_t position, last_position;
+
+  BEGIN_TEST;
+
+  total_frames_written = 0;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#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(r == 0 && stream);
+
+  /* stream position should not advance before starting playback */
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0 && position == 0);
+
+  delay(500);
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0 && position == 0);
+
+  /* stream position should advance during playback */
+  r = cubeb_stream_start(stream);
+  assert(r == 0);
+
+  /* XXX let start happen */
+  delay(500);
+
+  /* stream should have prefilled */
+  assert(total_frames_written > 0);
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+  last_position = position;
+
+  delay(500);
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+  assert(position >= last_position);
+  last_position = position;
+
+  /* stream position should not exceed total frames written */
+  for (i = 0; i < 5; ++i) {
+    r = cubeb_stream_get_position(stream, &position);
+    assert(r == 0);
+    assert(position >= last_position);
+    assert(position <= total_frames_written);
+    last_position = position;
+    delay(500);
+  }
+
+  /* test that the position is valid even when starting and
+   * stopping the stream.  */
+  for (i = 0; i < 5; ++i) {
+    r = cubeb_stream_stop(stream);
+    assert(r == 0);
+    r = cubeb_stream_get_position(stream, &position);
+    assert(r == 0);
+    assert(last_position < position);
+    last_position = position;
+    delay(500);
+    r = cubeb_stream_start(stream);
+    assert(r == 0);
+    delay(500);
+  }
+
+  assert(last_position != 0);
+
+  /* stream position should not advance after stopping playback */
+  r = cubeb_stream_stop(stream);
+  assert(r == 0);
+
+  /* XXX allow stream to settle */
+  delay(500);
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+  last_position = position;
+
+  delay(500);
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+  assert(position == last_position);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
+static int do_drain;
+static int got_drain;
+
+static long
+test_drain_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
+{
+  assert(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
+  if (do_drain == 1) {
+    do_drain = 2;
+    return 0;
+  }
+  /* once drain has started, callback must never be called again */
+  assert(do_drain != 2);
+#if (defined(_WIN32) || defined(__WIN32__))
+  memset(outputbuffer, 0, nframes * sizeof(float));
+#else
+  memset(outputbuffer, 0, nframes * sizeof(short));
+#endif
+  total_frames_written += nframes;
+  return nframes;
+}
+
+void
+test_drain_state_callback(cubeb_stream * /*stm*/, void * /*user_ptr*/, cubeb_state state)
+{
+  if (state == CUBEB_STATE_DRAINED) {
+    assert(!got_drain);
+    got_drain = 1;
+  }
+}
+
+static void
+test_drain(void)
+{
+  int r;
+  cubeb * ctx;
+  cubeb_stream * stream;
+  cubeb_stream_params params;
+  uint64_t position;
+
+  BEGIN_TEST;
+
+  total_frames_written = 0;
+
+  r = cubeb_init(&ctx, "test_sanity");
+  assert(r == 0 && ctx);
+
+  params.format = STREAM_FORMAT;
+  params.rate = STREAM_RATE;
+  params.channels = STREAM_CHANNELS;
+#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_drain_data_callback, test_drain_state_callback, &dummy);
+  assert(r == 0 && stream);
+
+  r = cubeb_stream_start(stream);
+  assert(r == 0);
+
+  delay(500);
+
+  do_drain = 1;
+
+  for (;;) {
+    r = cubeb_stream_get_position(stream, &position);
+    assert(r == 0);
+    if (got_drain) {
+      break;
+    } else {
+      assert(position <= total_frames_written);
+    }
+    delay(500);
+  }
+
+  r = cubeb_stream_get_position(stream, &position);
+  assert(r == 0);
+  assert(got_drain);
+
+  // Really, we should be able to rely on position reaching our final written frame, but
+  // for now let's make sure it doesn't continue beyond that point.
+  //assert(position <= total_frames_written);
+
+  cubeb_stream_destroy(stream);
+  cubeb_destroy(ctx);
+
+  END_TEST;
+}
+
 int is_windows_7()
 {
 #ifdef __MINGW32__
   printf("Warning: this test was built with MinGW.\n"
          "MinGW does not contain necessary version checking infrastructure. Claiming to be Windows 7, even if we're not.\n");
   return 1;
 #endif
 #if (defined(_WIN32) || defined(__WIN32__)) && ( !defined(__MINGW32__))
@@ -53,577 +623,54 @@ int is_windows_7()
   VER_SET_CONDITION(condition_mask, VER_MINORVERSION, VER_GREATER_EQUAL);
 
   return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition_mask);
 #else
   return 0;
 #endif
 }
 
-static int dummy;
-static std::atomic<uint64_t> total_frames_written;
-static int delay_callback;
-
-static long
-test_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
-{
-  EXPECT_TRUE(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
-#if (defined(_WIN32) || defined(__WIN32__))
-  memset(outputbuffer, 0, nframes * sizeof(float));
-#else
-  memset(outputbuffer, 0, nframes * sizeof(short));
-#endif
-
-  total_frames_written += nframes;
-  if (delay_callback) {
-    delay(10);
-  }
-  return nframes;
-}
-
-void
-test_state_callback(cubeb_stream * /*stm*/, void * /*user_ptr*/, cubeb_state /*state*/)
-{
-}
-
-TEST(cubeb, init_destroy_context)
-{
-  int r;
-  cubeb * ctx;
-  char const* backend_id;
-
-  r = cubeb_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);
-
-  cubeb_destroy(ctx);
-}
-
-TEST(cubeb, init_destroy_multiple_contexts)
+int
+main(int /*argc*/, char * /*argv*/[])
 {
-  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);
-    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_stream_params params;
-
-  r = cubeb_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;
-#if defined(__ANDROID__)
-  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
-#endif
-  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) {
-    ASSERT_TRUE(value > 0);
-  }
-
-  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");
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(ctx, nullptr);
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#if defined(__ANDROID__)
-  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_sanity");
 #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);
-
-  cubeb_stream_destroy(stream);
-  cubeb_destroy(ctx);
-}
-
-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");
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(ctx, nullptr);
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#if defined(__ANDROID__)
-  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
-#endif
-
-  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-    r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
-                          test_data_callback, test_state_callback, &dummy);
-    ASSERT_EQ(r, CUBEB_OK);
-    ASSERT_NE(stream[i], nullptr);
-  }
-
-  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-    cubeb_stream_destroy(stream[i]);
-  }
-
-  cubeb_destroy(ctx);
-}
-
-TEST(cubeb, configure_stream)
-{
-  int r;
-  cubeb * ctx;
-  cubeb_stream * stream;
-  cubeb_stream_params params;
-
-  r = cubeb_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
-#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_set_volume(stream, 1.0f);
-  ASSERT_TRUE(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);
+  test_init_destroy_context();
+  test_init_destroy_multiple_contexts();
+  test_context_variables();
+  test_init_destroy_stream();
+  test_init_destroy_multiple_streams();
+  test_configure_stream();
+  test_basic_stream_operations();
+  test_stream_position();
 
-  r = cubeb_stream_set_panning(stream, 0.0f);
-  ASSERT_TRUE(r == 0 || r == CUBEB_ERROR_NOT_SUPPORTED);
-
-  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;
-
-  r = cubeb_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;
-#if defined(__ANDROID__)
-  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
-#endif
-
-  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-    r = cubeb_stream_init(ctx, &stream[i], "test", NULL, NULL, NULL, &params, STREAM_LATENCY,
-                          test_data_callback, test_state_callback, &dummy);
-    ASSERT_EQ(r, CUBEB_OK);
-    ASSERT_NE(stream[i], nullptr);
-    if (early) {
-      r = cubeb_stream_start(stream[i]);
-      ASSERT_EQ(r, CUBEB_OK);
-    }
-  }
-
-
-  if (!early) {
-    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-      r = cubeb_stream_start(stream[i]);
-      ASSERT_EQ(r, CUBEB_OK);
-    }
-  }
-
-  if (delay_ms) {
-    delay(delay_ms);
-  }
-
-  if (!early) {
-    for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-      r = cubeb_stream_stop(stream[i]);
-      ASSERT_EQ(r, CUBEB_OK);
-    }
-  }
-
-  for (i = 0; i < ARRAY_LENGTH(stream); ++i) {
-    if (early) {
-      r = cubeb_stream_stop(stream[i]);
-      ASSERT_EQ(r, CUBEB_OK);
-    }
-    cubeb_stream_destroy(stream[i]);
-  }
-
-  cubeb_destroy(ctx);
-}
-
-TEST(cubeb, init_start_stop_destroy_multiple_streams)
-{
   /* Sometimes, when using WASAPI on windows 7 (vista and 8 are okay), and
    * calling Activate a lot on an AudioClient, 0x800700b7 is returned. This is
    * the HRESULT value for "Cannot create a file when that file already exists",
    * and is not documented as a possible return value for this call. Hence, we
    * try to limit the number of streams we create in this test. */
   if (!is_windows_7()) {
+    test_init_destroy_multiple_contexts_and_streams();
+
     delay_callback = 0;
     test_init_start_stop_destroy_multiple_streams(0, 0);
     test_init_start_stop_destroy_multiple_streams(1, 0);
     test_init_start_stop_destroy_multiple_streams(0, 150);
     test_init_start_stop_destroy_multiple_streams(1, 150);
     delay_callback = 1;
     test_init_start_stop_destroy_multiple_streams(0, 0);
     test_init_start_stop_destroy_multiple_streams(1, 0);
     test_init_start_stop_destroy_multiple_streams(0, 150);
     test_init_start_stop_destroy_multiple_streams(1, 150);
   }
-}
-
-TEST(cubeb, init_destroy_multiple_contexts_and_streams)
-{
-  size_t i, j;
-  int r;
-  cubeb * ctx[2];
-  cubeb_stream * stream[8];
-  cubeb_stream_params params;
-  size_t streams_per_ctx = ARRAY_LENGTH(stream) / ARRAY_LENGTH(ctx);
-  ASSERT_EQ(ARRAY_LENGTH(ctx) * streams_per_ctx, ARRAY_LENGTH(stream));
-
-  /* Sometimes, when using WASAPI on windows 7 (vista and 8 are okay), and
-   * calling Activate a lot on an AudioClient, 0x800700b7 is returned. This is
-   * the HRESULT value for "Cannot create a file when that file already exists",
-   * and is not documented as a possible return value for this call. Hence, we
-   * try to limit the number of streams we create in this test. */
-  if (is_windows_7())
-    return;
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#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");
-    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);
-    }
-  }
-
-  for (i = 0; i < ARRAY_LENGTH(ctx); ++i) {
-    for (j = 0; j < streams_per_ctx; ++j) {
-      cubeb_stream_destroy(stream[i * streams_per_ctx + j]);
-    }
-    cubeb_destroy(ctx[i]);
-  }
-}
-
-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");
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(ctx, nullptr);
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#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);
-
-  /* position and volume before stream has started */
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_EQ(position, 0u);
-
-  r = cubeb_stream_start(stream);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  /* position and volume after while stream running */
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  r = cubeb_stream_stop(stream);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  /* position and volume after stream has stopped */
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  cubeb_stream_destroy(stream);
-  cubeb_destroy(ctx);
-}
-
-TEST(cubeb, stream_position)
-{
-  size_t i;
-  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");
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(ctx, nullptr);
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#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);
-
-  /* stream position should not advance before starting playback */
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_EQ(position, 0u);
-
-  delay(500);
-
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_EQ(position, 0u);
-
-  /* stream position should advance during playback */
-  r = cubeb_stream_start(stream);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  /* XXX let start happen */
-  delay(500);
-
-  /* stream should have prefilled */
-  ASSERT_TRUE(total_frames_written.load() > 0);
-
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  last_position = position;
-
-  delay(500);
+  delay_callback = 0;
+  test_drain();
+/*
+  to implement:
+  test_eos_during_prefill();
+  test_stream_destroy_pending_drain();
+*/
+  printf("\n");
 
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_GE(position, last_position);
-  last_position = position;
-
-  /* stream position should not exceed total frames written */
-  for (i = 0; i < 5; ++i) {
-    r = cubeb_stream_get_position(stream, &position);
-    ASSERT_EQ(r, CUBEB_OK);
-    ASSERT_GE(position, last_position);
-    ASSERT_LE(position, total_frames_written.load());
-    last_position = position;
-    delay(500);
-  }
-
-  /* test that the position is valid even when starting and
-   * stopping the stream.  */
-  for (i = 0; i < 5; ++i) {
-    r = cubeb_stream_stop(stream);
-    ASSERT_EQ(r, CUBEB_OK);
-    r = cubeb_stream_get_position(stream, &position);
-    ASSERT_EQ(r, CUBEB_OK);
-    ASSERT_TRUE(last_position < position);
-    last_position = position;
-    delay(500);
-    r = cubeb_stream_start(stream);
-    ASSERT_EQ(r, CUBEB_OK);
-    delay(500);
-  }
-
-  ASSERT_NE(last_position, 0u);
-
-  /* stream position should not advance after stopping playback */
-  r = cubeb_stream_stop(stream);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  /* XXX allow stream to settle */
-  delay(500);
-
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  last_position = position;
-
-  delay(500);
-
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_EQ(position, last_position);
-
-  cubeb_stream_destroy(stream);
-  cubeb_destroy(ctx);
-}
-
-static std::atomic<int> do_drain;
-static std::atomic<int> got_drain;
-
-static long
-test_drain_data_callback(cubeb_stream * stm, void * user_ptr, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
-{
-  EXPECT_TRUE(stm && user_ptr == &dummy && outputbuffer && nframes > 0);
-  if (do_drain == 1) {
-    do_drain = 2;
-    return 0;
-  }
-  /* once drain has started, callback must never be called again */
-  EXPECT_TRUE(do_drain != 2);
-#if (defined(_WIN32) || defined(__WIN32__))
-  memset(outputbuffer, 0, nframes * sizeof(float));
-#else
-  memset(outputbuffer, 0, nframes * sizeof(short));
-#endif
-  total_frames_written += nframes;
-  return nframes;
+  return 0;
 }
-
-void
-test_drain_state_callback(cubeb_stream * /*stm*/, void * /*user_ptr*/, cubeb_state state)
-{
-  if (state == CUBEB_STATE_DRAINED) {
-    ASSERT_TRUE(!got_drain);
-    got_drain = 1;
-  }
-}
-
-TEST(cubeb, drain)
-{
-  int r;
-  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");
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(ctx, nullptr);
-
-  params.format = STREAM_FORMAT;
-  params.rate = STREAM_RATE;
-  params.channels = STREAM_CHANNELS;
-#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_drain_data_callback, test_drain_state_callback, &dummy);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_NE(stream, nullptr);
-
-  r = cubeb_stream_start(stream);
-  ASSERT_EQ(r, CUBEB_OK);
-
-  delay(500);
-
-  do_drain = 1;
-
-  for (;;) {
-    r = cubeb_stream_get_position(stream, &position);
-    ASSERT_EQ(r, CUBEB_OK);
-    if (got_drain) {
-      break;
-    } else {
-      ASSERT_LE(position, total_frames_written.load());
-    }
-    delay(500);
-  }
-
-  r = cubeb_stream_get_position(stream, &position);
-  ASSERT_EQ(r, CUBEB_OK);
-  ASSERT_TRUE(got_drain);
-
-  // Really, we should be able to rely on position reaching our final written frame, but
-  // for now let's make sure it doesn't continue beyond that point.
-  //ASSERT_LE(position, total_frames_written.load());
-
-  cubeb_stream_destroy(stream);
-  cubeb_destroy(ctx);
-}
-
-TEST(cubeb, DISABLED_eos_during_prefill)
-{
-  // This test needs to be implemented.
-}
-
-TEST(cubeb, DISABLED_stream_destroy_pending_drain)
-{
-  // This test needs to be implemented.
-}
rename from media/libcubeb/gtest/test_tone.cpp
rename to media/libcubeb/tests/test_tone.cpp
--- a/media/libcubeb/gtest/test_tone.cpp
+++ b/media/libcubeb/tests/test_tone.cpp
@@ -1,40 +1,45 @@
 /*
  * Copyright © 2011 Mozilla Foundation
  *
  * This program is made available under an ISC-style license.  See the
  * accompanying file LICENSE for details.
  */
 
 /* libcubeb api/function test. Plays a simple tone. */
-#include "gtest/gtest.h"
-#if !defined(_XOPEN_SOURCE)
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
 #define _XOPEN_SOURCE 600
-#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <math.h>
+#include <assert.h>
 #include <limits.h>
+
 #include "cubeb/cubeb.h"
 #include "common.h"
+#ifdef CUBEB_GECKO_BUILD
+#include "TestHarness.h"
+#endif
 
 #define SAMPLE_FREQUENCY 48000
 #if (defined(_WIN32) || defined(__WIN32__))
 #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE
 #else
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #endif
 
 /* store the phase of the generated waveform */
 struct cb_user_data {
   long position;
 };
 
-long data_cb_tone(cubeb_stream *stream, void *user, const void* /*inputbuffer*/, void *outputbuffer, long nframes)
+long data_cb(cubeb_stream *stream, void *user, const void* /*inputbuffer*/, void *outputbuffer, long nframes)
 {
   struct cb_user_data *u = (struct cb_user_data *)user;
 #if (defined(_WIN32) || defined(__WIN32__))
   float *b = (float *)outputbuffer;
 #else
   short *b = (short *)outputbuffer;
 #endif
   float t1, t2;
@@ -67,17 +72,17 @@ long data_cb_tone(cubeb_stream *stream, 
   }
   /* remember our phase to avoid clicking on buffer transitions */
   /* we'll still click if position overflows */
   u->position += nframes;
 
   return nframes;
 }
 
-void state_cb_tone(cubeb_stream *stream, void *user, cubeb_state state)
+void state_cb(cubeb_stream *stream, void *user, cubeb_state state)
 {
   struct cb_user_data *u = (struct cb_user_data *)user;
 
   if (stream == NULL || u == NULL)
     return;
 
   switch (state) {
   case CUBEB_STATE_STARTED:
@@ -88,51 +93,57 @@ void state_cb_tone(cubeb_stream *stream,
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-TEST(cubeb, tone)
+int main(int /*argc*/, char * /*argv*/[])
 {
+#ifdef CUBEB_GECKO_BUILD
+  ScopedXPCOM xpcom("test_tone");
+#endif
+
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
   struct cb_user_data *user_data;
   int r;
 
   r = cubeb_init(&ctx, "Cubeb tone example");
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb library\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   params.format = STREAM_FORMAT;
   params.rate = SAMPLE_FREQUENCY;
   params.channels = 1;
 
   user_data = (struct cb_user_data *) malloc(sizeof(*user_data));
   if (user_data == NULL) {
     fprintf(stderr, "Error allocating user data\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return CUBEB_ERROR;
   }
   user_data->position = 0;
 
   r = cubeb_stream_init(ctx, &stream, "Cubeb tone (mono)", NULL, NULL, NULL, &params,
-                        4096, data_cb_tone, state_cb_tone, user_data);
+                        4096, data_cb, state_cb, user_data);
   if (r != CUBEB_OK) {
     fprintf(stderr, "Error initializing cubeb stream\n");
-    ASSERT_EQ(r, CUBEB_OK);
+    return r;
   }
 
   cubeb_stream_start(stream);
   delay(500);
   cubeb_stream_stop(stream);
 
   cubeb_stream_destroy(stream);
   cubeb_destroy(ctx);
 
-  ASSERT_TRUE(user_data->position);
+  assert(user_data->position);
 
   free(user_data);
+
+  return CUBEB_OK;
 }
new file mode 100644
--- /dev/null
+++ b/media/libcubeb/tests/test_utils.cpp
@@ -0,0 +1,80 @@
+#include <cassert>
+#include "cubeb_utils.h"
+
+int test_auto_array()
+{
+  auto_array<uint32_t> array;
+  auto_array<uint32_t> array2(10);
+  uint32_t a[10];
+
+  assert(array2.length() == 0);
+  assert(array2.capacity() == 10);
+
+
+  for (uint32_t i = 0; i < 10; i++) {
+    a[i] = i;
+  }
+
+  assert(array.capacity() == 0);
+  assert(array.length() == 0);
+
+  array.push(a, 10);
+
+  assert(!array.reserve(9));
+
+  for (uint32_t i = 0; i < 10; i++) {
+    assert(array.data()[i] == i);
+  }
+
+  assert(array.capacity() == 10);
+  assert(array.length() == 10);
+
+  uint32_t b[10];
+
+  array.pop(b, 5);
+
+  assert(array.capacity() == 10);
+  assert(array.length() == 5);
+  for (uint32_t i = 0; i < 5; i++) {
+    assert(b[i] == i);
+    assert(array.data()[i] == 5 + i);
+  }
+  uint32_t* bb = b + 5;
+  array.pop(bb, 5);
+
+  assert(array.capacity() == 10);
+  assert(array.length() == 0);
+  for (uint32_t i = 0; i < 5; i++) {
+    assert(bb[i] == 5 + i);
+  }
+
+  assert(!array.pop(nullptr, 1));
+
+  array.push(a, 10);
+  array.push(a, 10);
+
+  for (uint32_t j = 0; j < 2; j++) {
+    for (uint32_t i = 0; i < 10; i++) {
+      assert(array.data()[10 * j + i] == i);
+    }
+  }
+  assert(array.length() == 20);
+  assert(array.capacity() == 20);
+  array.pop(nullptr, 5);
+
+  for (uint32_t i = 0; i < 5; i++) {
+    assert(array.data()[i] == 5 + i);
+  }
+
+  assert(array.length() == 15);
+  assert(array.capacity() == 20);
+
+  return 0;
+}
+
+
+int main()
+{
+  test_auto_array();
+  return 0;
+}
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -25,27 +25,26 @@ cp $1/src/cubeb_resampler.h src
 cp $1/src/cubeb_resampler_internal.h src
 cp $1/src/cubeb_ring_array.h src
 cp $1/src/cubeb_sndio.c src
 cp $1/src/cubeb_utils.h src
 cp $1/src/cubeb_utils_unix.h src
 cp $1/src/cubeb_utils_win.h src
 cp $1/src/cubeb_wasapi.cpp src
 cp $1/src/cubeb_winmm.c src
-cp $1/test/common.h gtest
-cp $1/test/test_audio.cpp gtest
-cp $1/test/test_devices.cpp gtest
-cp $1/test/test_duplex.cpp gtest
-cp $1/test/test_latency.cpp gtest
-cp $1/test/test_record.cpp gtest
-cp $1/test/test_resampler.cpp gtest
-cp $1/test/test_ring_array.cpp gtest
-cp $1/test/test_sanity.cpp gtest
-cp $1/test/test_tone.cpp gtest
-cp $1/test/test_utils.cpp gtest
+cp $1/test/common.h tests/common.h
+cp $1/test/test_audio.cpp tests/test_audio.cpp
+#cp $1/test/test_devices.c tests/test_devices.cpp
+cp $1/test/test_duplex.cpp tests/test_duplex.cpp
+cp $1/test/test_latency.cpp tests/test_latency.cpp
+cp $1/test/test_record.cpp tests/test_record.cpp
+cp $1/test/test_resampler.cpp tests/test_resampler.cpp
+cp $1/test/test_sanity.cpp tests/test_sanity.cpp
+cp $1/test/test_tone.cpp tests/test_tone.cpp
+cp $1/test/test_utils.cpp tests/test_utils.cpp
 
 if [ -d $1/.git ]; then
   rev=$(cd $1 && git rev-parse --verify HEAD)
   dirty=$(cd $1 && git diff-index --name-only HEAD)
 fi
 
 if [ -n "$rev" ]; then
   version=$rev
--- a/testing/cppunittest.ini
+++ b/testing/cppunittest.ini
@@ -80,20 +80,24 @@ skip-if = os == 'android' # Bug 1147631
 [signaling_unittests_standalone]
 [simpletokenbucket_unittest]
 [sockettransportservice_unittest]
 [test_AsXXX_helpers]
 [test_IHistory]
 [test_StatementCache]
 [test_asyncStatementExecution_transaction]
 [test_async_callbacks_with_spun_event_loops]
+[test_audio]
 [test_binding_params]
 [test_deadlock_detector]
 skip-if = os == 'b2g' || (os == 'android' && debug) # Bug 1054249
 [test_file_perms]
+[test_latency]
 [test_mutex]
+[test_sanity]
 [test_service_init_background_thread]
 [test_statement_scoper]
+[test_tone]
 [test_transaction_helper]
 [test_true_async]
 [test_unlock_notify]
 [transport_unittests]
 [turn_unittest]