Bug 1314496 - Update libcubeb to 8c41e564. r=padenot
authorMatthew Gregan <kinetik@flim.org>
Sun, 06 Nov 2016 10:43:11 +1300
changeset 351368 e80ad115dbb882562a6ad3f066d6b41a00232357
parent 351367 829525ed6a8d66b3f5e731c886fe68fdee093570
child 351369 d84108f190ee2ff550bd26d7ea07f8d843217298
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1314496
milestone52.0a1
Bug 1314496 - Update libcubeb to 8c41e564. r=padenot
media/libcubeb/README.md
media/libcubeb/README_MOZILLA
media/libcubeb/src/cubeb.c
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_log.h
media/libcubeb/src/cubeb_wasapi.cpp
media/libcubeb/tests/test_sanity.cpp
--- a/media/libcubeb/README.md
+++ b/media/libcubeb/README.md
@@ -1,5 +1,6 @@
 [![Build Status](https://travis-ci.org/kinetiknz/cubeb.svg?branch=master)](https://travis-ci.org/kinetiknz/cubeb)
+[![Build status](https://ci.appveyor.com/api/projects/status/osv2r0m1j1nt9csr/branch/master?svg=true)](https://ci.appveyor.com/project/kinetiknz/cubeb/branch/master)
 
 See INSTALL.md for build instructions.
 
 Licensed under an ISC-style license.  See LICENSE for details.
--- 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 352c0bed012a770ef65aee1e507704922ea80b0e.
+The git commit ID used was 8c41e5641df50a4b78650057872178a5860222f0.
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -379,28 +379,124 @@ int cubeb_stream_register_device_changed
 
   if (!stream->context->ops->stream_register_device_changed_callback) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
 
   return stream->context->ops->stream_register_device_changed_callback(stream, device_changed_callback);
 }
 
+static
+void log_device(cubeb_device_info * device_info)
+{
+  char devfmts[128] = "";
+  const char * devtype, * devstate, * devdeffmt;
+
+  switch (device_info->type) {
+    case CUBEB_DEVICE_TYPE_INPUT:
+      devtype = "input";
+      break;
+    case CUBEB_DEVICE_TYPE_OUTPUT:
+      devtype = "output";
+      break;
+    case CUBEB_DEVICE_TYPE_UNKNOWN:
+    default:
+      devtype = "unknown?";
+      break;
+  };
+
+  switch (device_info->state) {
+    case CUBEB_DEVICE_STATE_DISABLED:
+      devstate = "disabled";
+      break;
+    case CUBEB_DEVICE_STATE_UNPLUGGED:
+      devstate = "unplugged";
+      break;
+    case CUBEB_DEVICE_STATE_ENABLED:
+      devstate = "enabled";
+      break;
+    default:
+      devstate = "unknown?";
+      break;
+  };
+
+  switch (device_info->default_format) {
+    case CUBEB_DEVICE_FMT_S16LE:
+      devdeffmt = "S16LE";
+      break;
+    case CUBEB_DEVICE_FMT_S16BE:
+      devdeffmt = "S16BE";
+      break;
+    case CUBEB_DEVICE_FMT_F32LE:
+      devdeffmt = "F32LE";
+      break;
+    case CUBEB_DEVICE_FMT_F32BE:
+      devdeffmt = "F32BE";
+      break;
+    default:
+      devdeffmt = "unknown?";
+      break;
+  };
+
+  if (device_info->format & CUBEB_DEVICE_FMT_S16LE) {
+    strcat(devfmts, " S16LE");
+  }
+  if (device_info->format & CUBEB_DEVICE_FMT_S16BE) {
+    strcat(devfmts, " S16BE");
+  }
+  if (device_info->format & CUBEB_DEVICE_FMT_F32LE) {
+    strcat(devfmts, " F32LE");
+  }
+  if (device_info->format & CUBEB_DEVICE_FMT_F32BE) {
+    strcat(devfmts, " F32BE");
+  }
+
+  LOG("DeviceID: \"%s\"%s\n"
+      "\tName:\t\"%s\"\n"
+      "\tGroup:\t\"%s\"\n"
+      "\tVendor:\t\"%s\"\n"
+      "\tType:\t%s\n"
+      "\tState:\t%s\n"
+      "\tMaximum channels:\t%u\n"
+      "\tFormat:\t%s (0x%x) (default: %s)\n"
+      "\tRate:\t[%u, %u] (default: %u)\n"
+      "\tLatency: lo %u frames, hi %u frames",
+      device_info->device_id, device_info->preferred ? " (PREFERRED)" : "",
+      device_info->friendly_name,
+      device_info->group_id,
+      device_info->vendor_name,
+      devtype,
+      devstate,
+      device_info->max_channels,
+      (devfmts[0] == '\0') ? devfmts : devfmts + 1, (unsigned int)device_info->format, devdeffmt,
+      device_info->min_rate, device_info->max_rate, device_info->default_rate,
+      device_info->latency_lo, device_info->latency_hi);
+}
+
 int cubeb_enumerate_devices(cubeb * context,
                             cubeb_device_type devtype,
                             cubeb_device_collection ** collection)
 {
+  int rv;
   if ((devtype & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) == 0)
     return CUBEB_ERROR_INVALID_PARAMETER;
   if (collection == NULL)
     return CUBEB_ERROR_INVALID_PARAMETER;
   if (!context->ops->enumerate_devices)
     return CUBEB_ERROR_NOT_SUPPORTED;
 
-  return context->ops->enumerate_devices(context, devtype, collection);
+  rv = context->ops->enumerate_devices(context, devtype, collection);
+
+  if (g_log_callback) {
+    for (uint32_t i = 0; i < (*collection)->count; i++) {
+      log_device((*collection)->device[i]);
+    }
+  }
+
+  return rv;
 }
 
 int cubeb_device_collection_destroy(cubeb_device_collection * collection)
 {
   uint32_t i;
 
   if (collection == NULL)
     return CUBEB_ERROR_INVALID_PARAMETER;
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -289,18 +289,18 @@ audiounit_render_input(cubeb_stream * st
     audiounit_make_silent(&input_buffer_list.mBuffers[0]);
     return r;
   }
 
   /* Copy input data in linear buffer. */
   stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
                                  input_frames * stm->input_desc.mChannelsPerFrame);
 
-  LOGV("input:  buffers %d, size %d, channels %d, frames %d.",
-       input_buffer_list.mNumberBuffers,
+  LOGV("(%p) input:  buffers %d, size %d, channels %d, frames %d.",
+       stm, input_buffer_list.mNumberBuffers,
        input_buffer_list.mBuffers[0].mDataByteSize,
        input_buffer_list.mBuffers[0].mNumberChannels,
        input_frames);
 
   /* Advance input frame counter. */
   assert(input_frames > 0);
   stm->frames_read += input_frames;
 
@@ -308,26 +308,26 @@ audiounit_render_input(cubeb_stream * st
 }
 
 static OSStatus
 audiounit_input_callback(void * user_ptr,
                          AudioUnitRenderActionFlags * flags,
                          AudioTimeStamp const * tstamp,
                          UInt32 bus,
                          UInt32 input_frames,
-                         AudioBufferList * bufs)
+                         AudioBufferList * /* bufs */)
 {
   cubeb_stream * stm = static_cast<cubeb_stream *>(user_ptr);
-  long outframes, frames;
+  long outframes;
 
   assert(stm->input_unit != NULL);
   assert(AU_IN_BUS == bus);
 
   if (stm->shutdown) {
-    LOG("input shutdown");
+    LOG("(%p) input shutdown", stm);
     return noErr;
   }
 
   OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames);
   if (r != noErr) {
     return r;
   }
 
@@ -365,38 +365,39 @@ audiounit_input_callback(void * user_ptr
     return noErr;
   }
 
   return noErr;
 }
 
 static OSStatus
 audiounit_output_callback(void * user_ptr,
-                          AudioUnitRenderActionFlags * flags,
+                          AudioUnitRenderActionFlags * /* flags */,
                           AudioTimeStamp const * tstamp,
                           UInt32 bus,
                           UInt32 output_frames,
                           AudioBufferList * outBufferList)
 {
   assert(AU_OUT_BUS == bus);
   assert(outBufferList->mNumberBuffers == 1);
 
   cubeb_stream * stm = static_cast<cubeb_stream *>(user_ptr);
 
   stm->output_callback_in_a_row++;
 
-  LOGV("output(%p): buffers %d, size %d, channels %d, frames %d.", stm,
-       outBufferList->mNumberBuffers, outBufferList->mBuffers[0].mDataByteSize,
+  LOGV("(%p) output: buffers %d, size %d, channels %d, frames %d.",
+       stm, outBufferList->mNumberBuffers,
+       outBufferList->mBuffers[0].mDataByteSize,
        outBufferList->mBuffers[0].mNumberChannels, output_frames);
 
   long outframes = 0, input_frames = 0;
   void * output_buffer = NULL, * input_buffer = NULL;
 
   if (stm->shutdown) {
-    LOG("output shutdown.");
+    LOG("(%p) output shutdown.", stm);
     audiounit_make_silent(&outBufferList->mBuffers[0]);
     return noErr;
   }
 
   stm->current_latency_frames = audiotimestamp_to_latency(tstamp, stm);
   if (stm->draining) {
     OSStatus r = AudioOutputUnitStop(stm->output_unit);
     assert(r == 0);
@@ -415,17 +416,17 @@ audiounit_output_callback(void * user_pt
     /* If the output callback came first and this is a duplex stream, we need to
      * fill in some additional silence in the resampler.
      * Otherwise, if we had more than two callback in a row, or we're currently
      * switching, we add some silence as well to compensate for the fact that
      * we're lacking some input data. */
     if (stm->frames_read == 0 ||
         (stm->input_linear_buffer->length() == 0 &&
         (stm->output_callback_in_a_row > 2 || stm->switching_device))) {
-      LOG("Output callback came first send silent.");
+      LOG("(%p) Output callback came first send silent.", stm);
       stm->input_linear_buffer->push_silence(stm->input_buffer_frames *
                                              stm->input_desc.mChannelsPerFrame);
     }
     // The input buffer
     input_buffer = stm->input_linear_buffer->data();
     // Number of input frames in the buffer
     input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
   }
@@ -468,17 +469,17 @@ audiounit_output_callback(void * user_pt
       cubeb_pan_stereo_buffer_int((short*)output_buffer, outframes, panning);
     }
   }
   return noErr;
 }
 
 extern "C" {
 int
-audiounit_init(cubeb ** context, char const * context_name)
+audiounit_init(cubeb ** context, char const * /* context_name */)
 {
   cubeb * ctx;
 
   *context = NULL;
 
   ctx = (cubeb *)calloc(1, sizeof(cubeb));
   assert(ctx);
   // Placement new to call the ctors of cubeb members.
@@ -495,17 +496,17 @@ audiounit_init(cubeb ** context, char co
 
   *context = ctx;
 
   return CUBEB_OK;
 }
 }
 
 static char const *
-audiounit_get_backend_id(cubeb * ctx)
+audiounit_get_backend_id(cubeb * /* ctx */)
 {
   return "audiounit";
 }
 
 #if !TARGET_OS_IPHONE
 static int
 audiounit_get_output_device_id(AudioDeviceID * device_id)
 {
@@ -555,41 +556,41 @@ audiounit_get_input_device_id(AudioDevic
   if (r != noErr) {
     return CUBEB_ERROR;
   }
 
   return CUBEB_OK;
 }
 
 static OSStatus
-audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
+audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count,
                                      const AudioObjectPropertyAddress * addresses,
                                      void * user)
 {
   cubeb_stream * stm = (cubeb_stream*) user;
   int rv;
   bool was_running = false;
 
   stm->switching_device = true;
 
   // Note if the stream was running or not
   was_running = !stm->shutdown;
 
-  LOG("Audio device changed, %d events.", address_count);
+  LOG("(%p) Audio device changed, %d events.", stm, address_count);
   if (g_log_level) {
     for (UInt32 i = 0; i < address_count; i++) {
       switch(addresses[i].mSelector) {
         case kAudioHardwarePropertyDefaultOutputDevice:
-          LOG("%d mSelector == kAudioHardwarePropertyDefaultOutputDevice", i);
+          LOG("(%p) %d mSelector == kAudioHardwarePropertyDefaultOutputDevice", stm, i);
           break;
         case kAudioHardwarePropertyDefaultInputDevice:
-          LOG("%d mSelector == kAudioHardwarePropertyDefaultInputDevice", i);
+          LOG("(%p) %d mSelector == kAudioHardwarePropertyDefaultInputDevice", stm, i);
           break;
         case kAudioDevicePropertyDataSource:
-          LOG("%d mSelector == kAudioHardwarePropertyDataSource", i);
+          LOG("(%p) %d mSelector == kAudioHardwarePropertyDataSource", stm, i);
           break;
       }
     }
   }
 
   for (UInt32 i = 0; i < address_count; i++) {
     switch(addresses[i].mSelector) {
     case kAudioHardwarePropertyDefaultOutputDevice:
@@ -608,17 +609,17 @@ audiounit_property_listener_callback(Aud
   // This means the callback won't be called again.
   audiounit_stream_stop_internal(stm);
 
   {
     auto_lock lock(stm->mutex);
     close_audiounit_stream(stm);
     rv = setup_audiounit_stream(stm);
     if (rv != CUBEB_OK) {
-      LOG("Could not reopen a stream after switching.");
+      LOG("(%p) Could not reopen a stream after switching.", stm);
       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
       return noErr;
     }
 
     stm->frames_read = 0;
 
     // If the stream was running, start it again.
     if (was_running) {
@@ -859,17 +860,19 @@ audiounit_get_max_channel_count(cubeb * 
   }
 
   *max_channels = stream_format.mChannelsPerFrame;
 #endif
   return CUBEB_OK;
 }
 
 static int
-audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames)
+audiounit_get_min_latency(cubeb * /* ctx */,
+                          cubeb_stream_params /* params */,
+                          uint32_t * latency_frames)
 {
 #if TARGET_OS_IPHONE
   //TODO: [[AVAudioSession sharedInstance] inputLatency]
   return CUBEB_ERROR_NOT_SUPPORTED;
 #else
   AudioValueRange latency_range;
   if (audiounit_get_acceptable_latency_range(&latency_range) != CUBEB_OK) {
     LOG("Could not get acceptable latency range.");
@@ -879,17 +882,17 @@ audiounit_get_min_latency(cubeb * ctx, c
   *latency_frames = std::max<uint32_t>(latency_range.mMinimum,
                                        SAFE_MIN_LATENCY_FRAMES);
 #endif
 
   return CUBEB_OK;
 }
 
 static int
-audiounit_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
+audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
 {
 #if TARGET_OS_IPHONE
   //TODO
   return CUBEB_ERROR_NOT_SUPPORTED;
 #else
   UInt32 size;
   OSStatus r;
   Float64 fsamplerate;
@@ -980,17 +983,17 @@ audio_stream_desc_init(AudioStreamBasicD
   ss->mReserved = 0;
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_create_unit(AudioUnit * unit,
                       bool is_input,
-                      const cubeb_stream_params * stream_params,
+                      const cubeb_stream_params * /* stream_params */,
                       cubeb_devid device)
 {
   AudioComponentDescription desc;
   AudioComponent comp;
   UInt32 enable;
   AudioDeviceID devid;
   OSStatus rv;
 
@@ -1023,55 +1026,55 @@ audiounit_create_unit(AudioUnit * unit,
   if (rv != noErr) {
     PRINT_ERROR_CODE("AudioComponentInstanceNew", rv);
     return CUBEB_ERROR;
   }
 
   if (!use_default_output) {
     enable = 1;
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
-			      is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
-			      is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
+                              is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
+                              is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
     if (rv != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
       return CUBEB_ERROR;
     }
 
     enable = 0;
     rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
-			      is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
-			      is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
+                              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 == NULL) {
       assert(is_input);
       devid = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
     } else {
       devid = reinterpret_cast<intptr_t>(device);
     }
     int err = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice,
-				   kAudioUnitScope_Global,
-				   is_input ? AU_IN_BUS : AU_OUT_BUS,
-				   &devid, sizeof(AudioDeviceID));
+                                   kAudioUnitScope_Global,
+                                   is_input ? AU_IN_BUS : AU_OUT_BUS,
+                                   &devid, sizeof(AudioDeviceID));
     if (err != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", rv);
       return CUBEB_ERROR;
     }
   }
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
 {
-  if (stream->input_desc.mFormatFlags == kAudioFormatFlagIsSignedInteger) {
+  if (stream->input_desc.mFormatFlags & kAudioFormatFlagIsSignedInteger) {
     stream->input_linear_buffer = new auto_array_wrapper(
         new auto_array<short>(capacity *
                               stream->input_buffer_frames *
                               stream->input_desc.mChannelsPerFrame) );
   } else {
     stream->input_linear_buffer = new auto_array_wrapper(
         new auto_array<float>(capacity *
                               stream->input_buffer_frames *
@@ -1167,39 +1170,39 @@ audiounit_clamp_latency(cubeb_stream * s
                   SAFE_MIN_LATENCY_FRAMES);
 }
 
 static int
 setup_audiounit_stream(cubeb_stream * stm)
 {
   stm->mutex.assert_current_thread_owns();
 
-  AudioUnit input_unit;
-  AudioUnit output_unit;
   int r;
   AURenderCallbackStruct aurcbs_in;
   AURenderCallbackStruct aurcbs_out;
   UInt32 size;
 
   if (has_input(stm)) {
+    LOG("(%p) Opening input side, rate: %u", stm, stm->input_stream_params.rate);
     r = audiounit_create_unit(&stm->input_unit, true,
                               &stm->input_stream_params,
                               stm->input_device);
     if (r != CUBEB_OK) {
-      LOG("AudioUnit creation for input failed.");
+      LOG("(%p) AudioUnit creation for input failed.", stm);
       return r;
     }
   }
 
   if (has_output(stm)) {
+    LOG("(%p) Opening output side, rate: %u", stm, stm->input_stream_params.rate);
     r = audiounit_create_unit(&stm->output_unit, false,
                               &stm->output_stream_params,
                               stm->output_device);
     if (r != CUBEB_OK) {
-      LOG("AudioUnit creation for output failed.");
+      LOG("(%p) AudioUnit creation for output failed.", stm);
       return r;
     }
   }
 
   /* Setup Input Stream! */
   if (has_input(stm)) {
     /* Get input device sample rate. */
     AudioStreamBasicDescription input_hw_desc;
@@ -1214,23 +1217,23 @@ setup_audiounit_stream(cubeb_stream * st
       PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat", r);
       return CUBEB_ERROR;
     }
     stm->input_hw_rate = input_hw_desc.mSampleRate;
 
     /* Set format description according to the input params. */
     r = audio_stream_desc_init(&stm->input_desc, &stm->input_stream_params);
     if (r != CUBEB_OK) {
-      LOG("Setting format description for input failed.");
+      LOG("(%p) Setting format description for input failed.", stm);
       return r;
     }
 
     // Use latency to set buffer size
     stm->input_buffer_frames = stm->latency_frames;
-    LOG("Input buffer frame count %u.", unsigned(stm->input_buffer_frames));
+    LOG("(%p) Input buffer frame count %u.", stm, unsigned(stm->input_buffer_frames));
     r = AudioUnitSetProperty(stm->input_unit,
                              kAudioDevicePropertyBufferFrameSize,
                              kAudioUnitScope_Output,
                              AU_IN_BUS,
                              &stm->input_buffer_frames,
                              sizeof(UInt32));
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
@@ -1284,24 +1287,24 @@ setup_audiounit_stream(cubeb_stream * st
                              kAudioUnitScope_Global,
                              AU_OUT_BUS,
                              &aurcbs_in,
                              sizeof(aurcbs_in));
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback", r);
       return CUBEB_ERROR;
     }
-    LOG("Input audiounit init successfully.");
+    LOG("(%p) Input audiounit init successfully.", stm);
   }
 
   /* Setup Output Stream! */
   if (has_output(stm)) {
     r = audio_stream_desc_init(&stm->output_desc, &stm->output_stream_params);
     if (r != CUBEB_OK) {
-      LOG("Could not initialize the audio stream description.");
+      LOG("(%p) Could not initialize the audio stream description.", stm);
       return r;
     }
 
     /* Get output device sample rate. */
     AudioStreamBasicDescription output_hw_desc;
     size = sizeof(AudioStreamBasicDescription);
     memset(&output_hw_desc, 0, size);
     r = AudioUnitGetProperty(stm->output_unit,
@@ -1323,17 +1326,17 @@ setup_audiounit_stream(cubeb_stream * st
                              sizeof(AudioStreamBasicDescription));
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat", r);
       return CUBEB_ERROR;
     }
 
     // Use latency to calculate buffer size
     uint32_t output_buffer_frames = stm->latency_frames;
-    LOG("Output buffer frame count %u.", output_buffer_frames);
+    LOG("(%p) Output buffer frame count %u.", stm, output_buffer_frames);
     r = AudioUnitSetProperty(stm->output_unit,
                              kAudioDevicePropertyBufferFrameSize,
                              kAudioUnitScope_Input,
                              AU_OUT_BUS,
                              &output_buffer_frames,
                              sizeof(output_buffer_frames));
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
@@ -1348,17 +1351,17 @@ setup_audiounit_stream(cubeb_stream * st
                              kAudioUnitScope_Global,
                              AU_OUT_BUS,
                              &aurcbs_out,
                              sizeof(aurcbs_out));
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback", r);
       return CUBEB_ERROR;
     }
-    LOG("Output audiounit init successfully.");
+    LOG("(%p) Output audiounit init successfully.", stm);
   }
 
   // Setting the latency doesn't work well for USB headsets (eg. plantronics).
   // Keep the default latency for now.
 #if 0
   buffer_size = latency;
 
   /* Get the range of latency this particular device can work with, and clamp
@@ -1422,17 +1425,17 @@ setup_audiounit_stream(cubeb_stream * st
   stm->resampler = cubeb_resampler_create(stm,
                                           has_input(stm) ? &input_unconverted_params : NULL,
                                           has_output(stm) ? &stm->output_stream_params : NULL,
                                           target_sample_rate,
                                           stm->data_callback,
                                           stm->user_ptr,
                                           CUBEB_RESAMPLER_QUALITY_DESKTOP);
   if (!stm->resampler) {
-    LOG("Could not create resampler.");
+    LOG("(%p) Could not create resampler.", stm);
     return CUBEB_ERROR;
   }
 
   if (stm->input_unit != NULL) {
     r = AudioUnitInitialize(stm->input_unit);
     if (r != noErr) {
       PRINT_ERROR_CODE("AudioUnitInitialize/input", r);
       return CUBEB_ERROR;
@@ -1447,17 +1450,17 @@ setup_audiounit_stream(cubeb_stream * st
     }
   }
   return CUBEB_OK;
 }
 
 static int
 audiounit_stream_init(cubeb * context,
                       cubeb_stream ** stream,
-                      char const * stream_name,
+                      char const * /* stream_name */,
                       cubeb_devid input_device,
                       cubeb_stream_params * input_stream_params,
                       cubeb_devid output_device,
                       cubeb_stream_params * output_stream_params,
                       unsigned int latency_frames,
                       cubeb_data_callback data_callback,
                       cubeb_state_callback state_callback,
                       void * user_ptr)
@@ -1510,24 +1513,24 @@ audiounit_stream_init(cubeb * context,
     // It's not critical to lock here, because no other thread has been started
     // yet, but it allows to assert that the lock has been taken in
     // `setup_audiounit_stream`.
     auto_lock lock(stm->mutex);
     r = setup_audiounit_stream(stm);
   }
 
   if (r != CUBEB_OK) {
-    LOG("Could not setup the audiounit stream.");
+    LOG("(%p) Could not setup the audiounit stream.", stm);
     audiounit_stream_destroy(stm);
     return r;
   }
 
   r = audiounit_install_device_changed_callback(stm);
   if (r != CUBEB_OK) {
-    LOG("Could not install the device change callback.");
+    LOG("(%p) Could not install the device change callback.", stm);
     return r;
   }
 
   *stream = stm;
   LOG("Cubeb stream (%p) init successful.", stm);
   return CUBEB_OK;
 }
 
@@ -1560,17 +1563,17 @@ audiounit_stream_destroy(cubeb_stream * 
   {
     auto_lock lock(stm->mutex);
     close_audiounit_stream(stm);
   }
 
 #if !TARGET_OS_IPHONE
   int r = audiounit_uninstall_device_changed_callback(stm);
   if (r != CUBEB_OK) {
-    LOG("Could not uninstall the device changed callback");
+    LOG("(%p) Could not uninstall the device changed callback", stm);
   }
 #endif
 
   assert(stm->context->active_streams >= 1);
   stm->context->active_streams -= 1;
 
   stm->~cubeb_stream();
   free(stm);
@@ -1809,17 +1812,17 @@ int audiounit_stream_get_current_device(
 
   if (audiounit_get_input_device_id(&input_device_id) != CUBEB_OK) {
     return CUBEB_ERROR;
   }
 
   size = sizeof(UInt32);
   r = AudioObjectGetPropertyData(input_device_id, &datasource_address_input, 0, NULL, &size, &data);
   if (r != noErr) {
-    LOG("Error when getting device !");
+    LOG("(%p) Error when getting device !", stm);
     size = 0;
     data = 0;
   }
 
   (*device)->input_name = new char[size + 1];
   if (!(*device)->input_name) {
     return CUBEB_ERROR;
   }
@@ -1832,17 +1835,17 @@ int audiounit_stream_get_current_device(
 
   memcpy((*device)->input_name, strdata, size);
   (*device)->input_name[size] = '\0';
 
   return CUBEB_OK;
 #endif
 }
 
-int audiounit_stream_device_destroy(cubeb_stream * stream,
+int audiounit_stream_device_destroy(cubeb_stream * /* stream */,
                                     cubeb_device * device)
 {
   delete [] device->output_name;
   delete [] device->input_name;
   delete device;
   return CUBEB_OK;
 }
 
@@ -1901,20 +1904,20 @@ audiounit_strref_to_cstr_utf8(CFStringRe
   CFIndex len, size;
   char * ret;
   if (strref == NULL) {
     return NULL;
   }
 
   len = CFStringGetLength(strref);
   size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);
-  ret = new char[size];
+  ret = static_cast<char *>(malloc(size));
 
   if (!CFStringGetCString(strref, ret, size, kCFStringEncodingUTF8)) {
-    delete [] ret;
+    free(ret);
     ret = NULL;
   }
 
   return ret;
 }
 
 static uint32_t
 audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope)
@@ -2094,17 +2097,17 @@ audiounit_create_device_from_hwdev(Audio
     ret->latency_lo = 10 * ret->default_rate / 1000;  /* Default to  10ms */
     ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */
   }
 
   return ret;
 }
 
 static int
-audiounit_enumerate_devices(cubeb * context, cubeb_device_type type,
+audiounit_enumerate_devices(cubeb * /* context */, cubeb_device_type type,
                             cubeb_device_collection ** collection)
 {
   AudioObjectID * hwdevs = NULL;
   uint32_t i, hwdevcount = 0;
   OSStatus err;
 
   if ((err = audiounit_get_devices(&hwdevs, &hwdevcount)) != noErr) {
     return CUBEB_ERROR;
@@ -2186,17 +2189,17 @@ audiounit_get_devices_of_type(cubeb_devi
     /* For device in the given scope channel must be > 0. */
     if (audiounit_get_channel_count(devices[i], scope) > 0) {
       devices_in_scope[dev_count] = devices[i];
       ++dev_count;
     }
   }
 
   if (devid_array && dev_count > 0) {
-    *devid_array = static_cast<AudioObjectID *>(calloc(dev_count, sizeof(AudioObjectID)));
+    *devid_array = new AudioObjectID[dev_count];
     assert(*devid_array);
     memcpy(*devid_array, &devices_in_scope, dev_count * sizeof(AudioObjectID));
   }
   return dev_count;
 }
 
 static uint32_t
 audiounit_equal_arrays(AudioObjectID * left, AudioObjectID * right, uint32_t size)
@@ -2206,19 +2209,19 @@ audiounit_equal_arrays(AudioObjectID * l
     if (left[i] != right[i]) {
       return 0;
     }
   }
   return 1;
 }
 
 static OSStatus
-audiounit_collection_changed_callback(AudioObjectID inObjectID,
-                                      UInt32 inNumberAddresses,
-                                      const AudioObjectPropertyAddress * inAddresses,
+audiounit_collection_changed_callback(AudioObjectID /* inObjectID */,
+                                      UInt32 /* inNumberAddresses */,
+                                      const AudioObjectPropertyAddress * /* inAddresses */,
                                       void * inClientData)
 {
   cubeb * context = static_cast<cubeb *>(inClientData);
   auto_lock lock(context->mutex);
 
   if (context->collection_changed_callback == NULL) {
     /* Listener removed while waiting in mutex, abort. */
     return noErr;
--- a/media/libcubeb/src/cubeb_log.h
+++ b/media/libcubeb/src/cubeb_log.h
@@ -7,18 +7,24 @@
 
 #ifndef CUBEB_LOG
 #define CUBEB_LOG
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#if defined(__GNUC__) || defined(__clang__)
+#define PRINTF_FORMAT(fmt, args) __attribute__((format(printf, fmt, args)))
+#else
+#define PRINTF_FORMAT(fmt, args)
+#endif
+
 extern cubeb_log_level g_log_level;
-extern cubeb_log_callback g_log_callback;
+extern cubeb_log_callback g_log_callback PRINTF_FORMAT(1, 2);
 
 #ifdef __cplusplus
 }
 #endif
 
 #define LOGV(msg, ...) LOG_INTERNAL(CUBEB_LOG_VERBOSE, msg, ##__VA_ARGS__)
 #define LOG(msg, ...) LOG_INTERNAL(CUBEB_LOG_NORMAL, msg, ##__VA_ARGS__)
 
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -101,17 +101,17 @@ typedef BOOL (WINAPI *revert_mm_thread_c
 
 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 * wstr_to_utf8(const wchar_t * str);
-static const wchar_t * utf8_to_wstr(char* 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. */
@@ -614,19 +614,21 @@ bool get_output_buffer(cubeb_stream * st
   if (FAILED(hr)) {
     LOG("Failed to get padding: %x", hr);
     return false;
   }
   XASSERT(padding_out <= stm->output_buffer_frame_count);
 
   if (stm->draining) {
     if (padding_out == 0) {
+      LOG("Draining finished.");
       stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
       return false;
     }
+    LOG("Draining.");
     return true;
   }
 
   frame_count = stm->output_buffer_frame_count - padding_out;
   BYTE * output_buffer;
 
   hr = stm->render_client->GetBuffer(frame_count, &output_buffer);
   if (FAILED(hr)) {
@@ -679,16 +681,19 @@ refill_callback_duplex(cubeb_stream * st
   double output_duration = double(output_frames) / stm->output_mix_params.rate;
   double input_duration = double(stm->linear_input_buffer.length() / stm->input_stream_params.channels) / stm->input_mix_params.rate;
   if (input_duration < output_duration) {
     size_t padding = size_t(round((output_duration - input_duration) * stm->input_mix_params.rate));
     LOG("padding silence: out=%f in=%f pad=%u", output_duration, input_duration, padding);
     stm->linear_input_buffer.push_front_silence(padding * stm->input_stream_params.channels);
   }
 
+  LOGV("Duplex callback: input frames: %zu, output frames: %zu",
+       stm->linear_input_buffer.length(), output_frames);
+
   refill(stm,
          stm->linear_input_buffer.data(),
          stm->linear_input_buffer.length(),
          output_buffer,
          output_frames);
 
   stm->linear_input_buffer.clear();
 
@@ -712,16 +717,18 @@ refill_callback_input(cubeb_stream * stm
     return rv;
   }
 
   // This can happen at the very beginning of the stream.
   if (!stm->linear_input_buffer.length()) {
     return true;
   }
 
+  LOGV("Input callback: input frames: %zu", stm->linear_input_buffer.length());
+
   long read = refill(stm,
                      stm->linear_input_buffer.data(),
                      stm->linear_input_buffer.length(),
                      nullptr,
                      0);
 
   consumed_all_buffer = read == stm->linear_input_buffer.length();
 
@@ -749,16 +756,20 @@ refill_callback_output(cubeb_stream * st
     return true;
   }
 
   long got = refill(stm,
                     nullptr,
                     0,
                     output_buffer,
                     output_frames);
+
+  LOGV("Output callback: output frames requested: %zu, got %ld",
+       output_frames, got);
+
   XASSERT(got >= 0);
   XASSERT(got == output_frames || stm->draining);
 
   hr = stm->render_client->ReleaseBuffer(got, 0);
   if (FAILED(hr)) {
     LOG("failed to release buffer: %x", hr);
     return false;
   }
@@ -819,58 +830,67 @@ wasapi_stream_render_loop(LPVOID stream)
          shutdown. */
       if (stm->draining) {
         stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
       }
       continue;
     }
     case WAIT_OBJECT_0 + 1: { /* reconfigure */
       XASSERT(stm->output_client || stm->input_client);
+      LOG("Reconfiguring the stream");
       /* Close the stream */
       if (stm->output_client) {
         stm->output_client->Stop();
+        LOG("Output stopped.");
       }
       if (stm->input_client) {
         stm->input_client->Stop();
+        LOG("Input stopped.");
       }
       {
         auto_lock lock(stm->stream_reset_lock);
         close_wasapi_stream(stm);
+        LOG("Stream closed.");
         /* Reopen a stream and start it immediately. This will automatically pick the
            new default device for this role. */
         int r = setup_wasapi_stream(stm);
         if (r != CUBEB_OK) {
+          LOG("Error setting up the stream during reconfigure.");
           /* Don't destroy the stream here, since we expect the caller to do
              so after the error has propagated via the state callback. */
           is_playing = false;
           hr = E_FAIL;
           continue;
         }
+        LOG("Stream setup successfuly.");
       }
       XASSERT(stm->output_client || stm->input_client);
       if (stm->output_client) {
         stm->output_client->Start();
+        LOG("Output started after reconfigure.");
       }
       if (stm->input_client) {
         stm->input_client->Start();
+        LOG("Input started after reconfigure.");
       }
       break;
     }
     case WAIT_OBJECT_0 + 2:  /* refill */
       XASSERT(has_input(stm) && has_output(stm) ||
               !has_input(stm) && has_output(stm));
       is_playing = stm->refill_callback(stm);
       break;
     case WAIT_OBJECT_0 + 3: /* input available */
       if (has_input(stm) && has_output(stm)) { continue; }
       is_playing = stm->refill_callback(stm);
       break;
     case WAIT_TIMEOUT:
       XASSERT(stm->shutdown_event == wait_array[0]);
       if (++timeout_count >= timeout_limit) {
+        LOG("Render loop reached the timeout limit.");
         is_playing = false;
         hr = E_FAIL;
       }
       break;
     default:
       LOG("case %d not handled in render loop.", waitResult);
       abort();
     }
@@ -1111,17 +1131,19 @@ int wasapi_init(cubeb ** context, char c
 
   return CUBEB_OK;
 }
 }
 
 namespace {
 void stop_and_join_render_thread(cubeb_stream * stm)
 {
+  LOG("Stop and join render thread.");
   if (!stm->thread) {
+    LOG("No thread present.");
     return;
   }
 
   BOOL ok = SetEvent(stm->shutdown_event);
   if (!ok) {
     LOG("Destroy SetEvent failed: %d", GetLastError());
   }
 
@@ -1133,16 +1155,18 @@ void stop_and_join_render_thread(cubeb_s
      * process. */
     LOG("Destroy WaitForSingleObject on thread timed out,"
         " leaking the thread: %d", GetLastError());
   }
   if (r == WAIT_FAILED) {
     LOG("Destroy WaitForSingleObject on thread failed: %d", GetLastError());
   }
 
+  LOG("Closing thread.");
+
   CloseHandle(stm->thread);
   stm->thread = NULL;
 
   CloseHandle(stm->shutdown_event);
   stm->shutdown_event = 0;
 }
 
 void wasapi_destroy(cubeb * context)
@@ -1241,16 +1265,18 @@ wasapi_get_min_latency(cubeb * ctx, cube
   LOG("default device period: %lld", default_period);
 
   /* According to the docs, the best latency we can achieve is by synchronizing
      the stream and the engine.
      http://msdn.microsoft.com/en-us/library/windows/desktop/dd370871%28v=vs.85%29.aspx */
 
   *latency_frames = hns_to_frames(params.rate, default_period);
 
+  LOG("Minimum latency in frames: %u", *latency_frames);
+
   SafeRelease(client);
 
   return CUBEB_OK;
 }
 
 int
 wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
@@ -1279,16 +1305,18 @@ wasapi_get_preferred_sample_rate(cubeb *
   hr = client->GetMixFormat(&mix_format);
   if (FAILED(hr)) {
     SafeRelease(client);
     return CUBEB_ERROR;
   }
 
   *rate = mix_format->nSamplesPerSec;
 
+  LOG("Preferred sample rate for output: %u", *rate);
+
   CoTaskMemFree(mix_format);
   SafeRelease(client);
 
   return CUBEB_OK;
 }
 
 void wasapi_stream_destroy(cubeb_stream * stm);
 
@@ -1381,18 +1409,17 @@ 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) {
-      std::unique_ptr<const wchar_t> id;
-      id.reset(utf8_to_wstr(reinterpret_cast<char*>(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 {
       hr = get_default_endpoint(&device, direction);
@@ -1495,16 +1522,17 @@ int setup_wasapi_stream(cubeb_stream * s
 {
   HRESULT hr;
   int rv;
 
   stm->stream_reset_lock.assert_current_thread_owns();
 
   auto_com com;
   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("Setup capture: device=%x", (int)stm->input_device);
     rv = setup_wasapi_stream_one_side(stm,
@@ -1513,16 +1541,17 @@ int setup_wasapi_stream(cubeb_stream * s
                                       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("Setup render: device=%x", (int)stm->output_device);
     rv = setup_wasapi_stream_one_side(stm,
                                       &stm->output_stream_params,
@@ -1530,16 +1559,17 @@ int setup_wasapi_stream(cubeb_stream * s
                                       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) {
+      LOG("Failure to open the output side.");
       return rv;
     }
 
     hr = stm->output_client->GetService(__uuidof(IAudioStreamVolume),
                                         (void **)&stm->audio_stream_volume);
     if (FAILED(hr)) {
       LOG("Could not get the IAudioStreamVolume: %x", hr);
       return CUBEB_ERROR;
@@ -1550,16 +1580,17 @@ int setup_wasapi_stream(cubeb_stream * s
                                         (void **)&stm->audio_clock);
     if (FAILED(hr)) {
       LOG("Could not get the IAudioClock: %x", hr);
       return CUBEB_ERROR;
     }
 
     /* Restore the stream volume over a device change. */
     if (stream_set_volume(stm, stm->volume) != CUBEB_OK) {
+      LOG("Could not set the volume.");
       return CUBEB_ERROR;
     }
   }
 
   /* If we have both input and output, we resample to
    * the highest sample rate available. */
   int32_t target_sample_rate;
   if (has_input(stm) && has_output(stm)) {
@@ -1567,16 +1598,18 @@ int setup_wasapi_stream(cubeb_stream * s
     target_sample_rate = stm->input_stream_params.rate;
   } else if (has_input(stm)) {
     target_sample_rate = stm->input_stream_params.rate;
   } else {
     XASSERT(has_output(stm));
     target_sample_rate = stm->output_stream_params.rate;
   }
 
+  LOG("Target sample rate: %d", target_sample_rate);
+
   /* If we are playing/capturing a mono stream, we only resample one channel,
    and copy it over, so we are always resampling the number
    of channels of the stream, not the number of channels
    that WASAPI wants. */
   cubeb_stream_params input_params = stm->input_mix_params;
   input_params.channels = stm->input_stream_params.channels;
   cubeb_stream_params output_params = stm->output_mix_params;
   output_params.channels = stm->output_stream_params.channels;
@@ -1623,16 +1656,20 @@ wasapi_stream_init(cubeb * context, cube
   if (!com.ok()) {
     return CUBEB_ERROR;
   }
 
   XASSERT(context && stream && (input_stream_params || output_stream_params));
 
   if (output_stream_params && output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE ||
       input_stream_params && input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE) {
+    LOG("Invalid format, %p %p %d %d",
+        output_stream_params, input_stream_params,
+        output_stream_params && output_stream_params->format,
+        input_stream_params && input_stream_params->format);
     return CUBEB_ERROR_INVALID_FORMAT;
   }
 
   cubeb_stream * stm = (cubeb_stream *)calloc(1, sizeof(cubeb_stream));
 
   XASSERT(stm);
 
   stm->context = context;
@@ -1945,36 +1982,36 @@ int wasapi_stream_set_volume(cubeb_strea
 static char *
 wstr_to_utf8(LPCWSTR str)
 {
   char * ret = NULL;
   int size;
 
   size = ::WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, 0, NULL, NULL);
   if (size > 0) {
-    ret =  new char[size];
+    ret = static_cast<char *>(malloc(size));
     ::WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, size, NULL, NULL);
   }
 
   return ret;
 }
 
-static const wchar_t *
+static std::unique_ptr<const wchar_t[]>
 utf8_to_wstr(char* str)
 {
-  wchar_t * ret = nullptr;
+  std::unique_ptr<wchar_t[]> ret;
   int size;
 
-  size = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, 0);
+  size = ::MultiByteToWideChar(CP_UTF8, 0, str, -1, nullptr, 0);
   if (size > 0) {
-    ret = new wchar_t[size];
-    ::MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, size);
+    ret.reset(new wchar_t[size]);
+    ::MultiByteToWideChar(CP_UTF8, 0, str, -1, ret.get(), size);
   }
 
-  return ret;
+  return std::move(ret);
 }
 
 static IMMDevice *
 wasapi_get_device_node(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
 {
   IMMDevice * ret = NULL;
   IDeviceTopology * devtopo = NULL;
   IConnector * connector = NULL;
--- a/media/libcubeb/tests/test_sanity.cpp
+++ b/media/libcubeb/tests/test_sanity.cpp
@@ -466,16 +466,31 @@ test_stream_position(void)
     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);