Bug 1274479 - Update libcubeb. r=padenot
authorMatthew Gregan <kinetik@flim.org>
Tue, 13 Sep 2016 13:23:46 +1200
changeset 339400 db9b0546e3d48632b0d33361786dc894d23f9dd1
parent 339398 aa63a2a40325d64c9121139d40c0170bda1e5482
child 339401 c75b43f81d5c17eed6f888b1b0de1cfe06bec333
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspadenot
bugs1274479
milestone51.0a1
Bug 1274479 - Update libcubeb. r=padenot
media/libcubeb/README_MOZILLA
media/libcubeb/bug1278612.patch
media/libcubeb/include/cubeb.h
media/libcubeb/src/cubeb-internal.h
media/libcubeb/src/cubeb.c
media/libcubeb/src/cubeb_audiounit.cpp
media/libcubeb/src/cubeb_jack.cpp
media/libcubeb/src/cubeb_resampler.cpp
media/libcubeb/src/cubeb_utils_unix.h
media/libcubeb/src/cubeb_wasapi.cpp
media/libcubeb/src/cubeb_winmm.c
media/libcubeb/tests/test_audio.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/update.sh
--- 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 e4074131e4d422bfe260d29ab0a49fc368406ef4.
+The git commit ID used was 92b4afa6ae9f0969e77d59a8f9de9ab36acd7d7f.
deleted file mode 100644
--- a/media/libcubeb/bug1278612.patch
+++ /dev/null
@@ -1,136 +0,0 @@
-diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp
---- a/media/libcubeb/src/cubeb_audiounit.cpp
-+++ b/media/libcubeb/src/cubeb_audiounit.cpp
-@@ -48,22 +48,16 @@
- typedef UInt32  AudioFormatFlags;
- #endif
- 
- #define CUBEB_STREAM_MAX 8
- 
- #define AU_OUT_BUS    0
- #define AU_IN_BUS     1
- 
--#if TARGET_OS_IPHONE
--#define CUBEB_AUDIOUNIT_SUBTYPE kAudioUnitSubType_RemoteIO
--#else
--#define CUBEB_AUDIOUNIT_SUBTYPE kAudioUnitSubType_HALOutput
--#endif
--
- //#define LOGGING_ENABLED
- #ifdef LOGGING_ENABLED
- #define LOG(...) do {                           \
-     fprintf(stderr, __VA_ARGS__);               \
-     fprintf(stderr, "(line: %d)\n", __LINE__);  \
-   } while(0)
- #else
- #define LOG(...)
-@@ -905,63 +899,79 @@ audiounit_create_unit(AudioUnit * unit,
- {
-   AudioComponentDescription desc;
-   AudioComponent comp;
-   UInt32 enable;
-   AudioDeviceID devid;
-   OSStatus rv;
- 
-   desc.componentType = kAudioUnitType_Output;
--  desc.componentSubType = CUBEB_AUDIOUNIT_SUBTYPE;
-+#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 == NULL && !is_input;
-+  if (use_default_output) {
-+    desc.componentSubType = kAudioUnitSubType_DefaultOutput;
-+  } else {
-+    desc.componentSubType = kAudioUnitSubType_HALOutput;
-+  }
-+#endif
-   desc.componentManufacturer = kAudioUnitManufacturer_Apple;
-   desc.componentFlags = 0;
-   desc.componentFlagsMask = 0;
-   comp = AudioComponentFindNext(NULL, &desc);
-   if (comp == NULL) {
-     LOG("Could not find matching audio hardware.");
-     return CUBEB_ERROR;
-   }
- 
-   rv = AudioComponentInstanceNew(comp, unit);
-   if (rv != noErr) {
-     PRINT_ERROR_CODE("AudioComponentInstanceNew", rv);
-     return CUBEB_ERROR;
-   }
- 
--  enable = 1;
--  rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
--           is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
--           is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
--  if (rv != noErr) {
--    PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
--    return CUBEB_ERROR;
--  }
-+  if (!use_default_output) {
-+    enable = 1;
-+    rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
-+			      is_input ? kAudioUnitScope_Input : kAudioUnitScope_Output,
-+			      is_input ? AU_IN_BUS : AU_OUT_BUS, &enable, sizeof(UInt32));
-+    if (rv != noErr) {
-+      PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
-+      return CUBEB_ERROR;
-+    }
- 
--  enable = 0;
--  rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
--            is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
--            is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
--  if (rv != noErr) {
--    PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
--    return CUBEB_ERROR;
--  }
-+    enable = 0;
-+    rv = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_EnableIO,
-+			      is_input ? kAudioUnitScope_Output : kAudioUnitScope_Input,
-+			      is_input ? AU_OUT_BUS : AU_IN_BUS, &enable, sizeof(UInt32));
-+    if (rv != noErr) {
-+      PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_EnableIO", rv);
-+      return CUBEB_ERROR;
-+    }
- 
--  if (device == NULL) {
--    devid = audiounit_get_default_device_id(is_input ? CUBEB_DEVICE_TYPE_INPUT
--                                                     : CUBEB_DEVICE_TYPE_OUTPUT);
--  } 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));
--  if (err != noErr) {
--    PRINT_ERROR_CODE("AudioUnitSetProperty/kAudioOutputUnitProperty_CurrentDevice", 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));
-+    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)
- {
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -391,27 +391,27 @@ int cubeb_get_preferred_sample_rate(cube
  *  been destroyed.
     @param context A pointer to the cubeb context.*/
 void cubeb_destroy(cubeb * context);
 
 /** Initialize a stream associated with the supplied application context.
     @param context A pointer to the cubeb context.
     @param stream An out parameter to be filled with the an opaque pointer to a
                   cubeb stream.
-    @param stream_name A name for this stream. 
+    @param stream_name A name for this stream.
     @param input_device Device for the input side of the stream. If NULL the
                         default input device is used.
     @param input_stream_params Parameters for the input side of the stream, or
                                NULL if this stream is output only.
     @param output_device Device for the output side of the stream. If NULL the
                          default output device is used.
     @param output_stream_params Parameters for the output side of the stream, or
                                 NULL if this stream is input only.
-    @param latency Stream latency in frames.  Valid range
-                   is [1, 96000].
+    @param latency_frames Stream latency in frames.  Valid range
+                          is [1, 96000].
     @param data_callback Will be called to preroll data before playback is
                          started by cubeb_stream_start.
     @param state_callback A pointer to a state callback.
     @param user_ptr A pointer that will be passed to the callbacks. This pointer
                     must outlive the life time of the stream.
     @retval CUBEB_OK
     @retval CUBEB_ERROR
     @retval CUBEB_ERROR_INVALID_FORMAT
--- a/media/libcubeb/src/cubeb-internal.h
+++ b/media/libcubeb/src/cubeb-internal.h
@@ -6,16 +6,39 @@
  */
 #if !defined(CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5)
 #define CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5
 
 #include "cubeb/cubeb.h"
 #include <stdio.h>
 #include <string.h>
 
+#ifdef __clang__
+#ifndef CLANG_ANALYZER_NORETURN
+#if __has_feature(attribute_analyzer_noreturn)
+#define CLANG_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
+#else
+#define CLANG_ANALYZER_NORETURN
+#endif // ifndef CLANG_ANALYZER_NORETURN
+#endif // __has_feature(attribute_analyzer_noreturn)
+#else // __clang__
+#define CLANG_ANALYZER_NORETURN
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* Crash the caller.  */
+void cubeb_crash() CLANG_ANALYZER_NORETURN;
+
+#if defined(__cplusplus)
+}
+#endif
+
 struct cubeb_ops {
   int (* init)(cubeb ** context, char const * context_name);
   char const * (* get_backend_id)(cubeb * context);
   int (* get_max_channel_count)(cubeb * context, uint32_t * max_channels);
   int (* get_min_latency)(cubeb * context,
                           cubeb_stream_params params,
                           uint32_t * latency_ms);
   int (* get_preferred_sample_rate)(cubeb * context, uint32_t * rate);
@@ -47,17 +70,16 @@ struct cubeb_ops {
   int (* stream_register_device_changed_callback)(cubeb_stream * stream,
                                                   cubeb_device_changed_callback device_changed_callback);
   int (* register_device_collection_changed)(cubeb * context,
                                              cubeb_device_type devtype,
                                              cubeb_device_collection_changed_callback callback,
                                              void * user_ptr);
 };
 
-#define XASSERT(expr) do {                                              \
-    if (!(expr)) {                                                      \
+#define XASSERT(expr) do {                                                     \
+    if (!(expr)) {                                                             \
       fprintf(stderr, "%s:%d - fatal error: %s\n", __FILE__, __LINE__, #expr); \
-      *((volatile int *) NULL) = 0;                                     \
-      abort();                                                          \
-    }                                                                   \
+      cubeb_crash();                                                           \
+    }                                                                          \
   } while (0)
 
 #endif /* CUBEB_INTERNAL_0eb56756_4e20_4404_a76d_42bf88cd15a5 */
--- a/media/libcubeb/src/cubeb.c
+++ b/media/libcubeb/src/cubeb.c
@@ -28,25 +28,19 @@ struct cubeb_stream {
 int pulse_init(cubeb ** context, char const * context_name);
 #endif
 #if defined(USE_JACK)
 int jack_init (cubeb ** context, char const * context_name);
 #endif
 #if defined(USE_ALSA)
 int alsa_init(cubeb ** context, char const * context_name);
 #endif
-#if defined(USE_AUDIOQUEUE)
-int audioqueue_init(cubeb ** context, char const * context_name);
-#endif
 #if defined(USE_AUDIOUNIT)
 int audiounit_init(cubeb ** context, char const * context_name);
 #endif
-#if defined(USE_DIRECTSOUND)
-int directsound_init(cubeb ** context, char const * context_name);
-#endif
 #if defined(USE_WINMM)
 int winmm_init(cubeb ** context, char const * context_name);
 #endif
 #if defined(USE_WASAPI)
 int wasapi_init(cubeb ** context, char const * context_name);
 #endif
 #if defined(USE_SNDIO)
 int sndio_init(cubeb ** context, char const * context_name);
@@ -124,28 +118,22 @@ cubeb_init(cubeb ** context, char const 
     pulse_init,
 #endif
 #if defined(USE_ALSA)
     alsa_init,
 #endif
 #if defined(USE_AUDIOUNIT)
     audiounit_init,
 #endif
-#if defined(USE_AUDIOQUEUE)
-    audioqueue_init,
-#endif
 #if defined(USE_WASAPI)
     wasapi_init,
 #endif
 #if defined(USE_WINMM)
     winmm_init,
 #endif
-#if defined(USE_DIRECTSOUND)
-    directsound_init,
-#endif
 #if defined(USE_SNDIO)
     sndio_init,
 #endif
 #if defined(USE_OPENSL)
     opensl_init,
 #endif
 #if defined(USE_AUDIOTRACK)
     audiotrack_init,
@@ -449,8 +437,15 @@ int cubeb_register_device_collection_cha
 
   if (!context->ops->register_device_collection_changed) {
     return CUBEB_ERROR_NOT_SUPPORTED;
   }
 
   return context->ops->register_device_collection_changed(context, devtype, callback, user_ptr);
 }
 
+void cubeb_crash()
+{
+  abort();
+  *((volatile int *) NULL) = 0;
+}
+
+
--- a/media/libcubeb/src/cubeb_audiounit.cpp
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
@@ -25,16 +25,17 @@
 #include "cubeb_panner.h"
 #if !TARGET_OS_IPHONE
 #include "cubeb_osx_run_loop.h"
 #endif
 #include "cubeb_resampler.h"
 #include "cubeb_ring_array.h"
 #include "cubeb_utils.h"
 #include <algorithm>
+#include <atomic>
 
 #if !defined(kCFCoreFoundationVersionNumber10_7)
 /* From CoreFoundation CFBase.h */
 #define kCFCoreFoundationVersionNumber10_7 635.00
 #endif
 
 #if !TARGET_OS_IPHONE && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
 #define AudioComponent Component
@@ -175,17 +176,17 @@ struct cubeb_stream {
   /* Frame counters */
   uint64_t frames_played;
   uint64_t frames_queued;
   uint64_t frames_read;
   int shutdown;
   int draining;
   uint64_t current_latency_frames;
   uint64_t hw_latency_frames;
-  float panning;
+  std::atomic<float> panning;
   cubeb_resampler * resampler;
 };
 
 #if TARGET_OS_IPHONE
 typedef UInt32 AudioDeviceID;
 typedef UInt32 AudioObjectID;
 
 #define AudioGetCurrentHostTime mach_absolute_time
@@ -404,17 +405,18 @@ audiounit_output_callback(void * user_pt
   }
 
   size_t outbpf = stm->output_desc.mBytesPerFrame;
   stm->draining = outframes < output_frames;
   stm->frames_played = stm->frames_queued;
   stm->frames_queued += outframes;
 
   AudioFormatFlags outaff = stm->output_desc.mFormatFlags;
-  float panning = (stm->output_desc.mChannelsPerFrame == 2) ? stm->panning : 0.0f;
+  float panning = (stm->output_desc.mChannelsPerFrame == 2) ?
+      stm->panning.load(std::memory_order_relaxed) : 0.0f;
 
   /* Post process output samples. */
   if (stm->draining) {
     /* Clear missing frames (silence) */
     memset((uint8_t*)output_buffer + outframes * outbpf, 0, (output_frames - outframes) * outbpf);
   }
   /* Pan stereo. */
   if (panning != 0.0f) {
@@ -1608,21 +1610,17 @@ int audiounit_stream_set_volume(cubeb_st
 }
 
 int audiounit_stream_set_panning(cubeb_stream * stm, float panning)
 {
   if (stm->output_desc.mChannelsPerFrame > 2) {
     return CUBEB_ERROR_INVALID_PARAMETER;
   }
 
-  {
-    auto_lock lock(stm->mutex);
-    stm->panning = panning;
-  }
-
+  stm->panning.store(panning, std::memory_order_relaxed);
   return CUBEB_OK;
 }
 
 int audiounit_stream_get_current_device(cubeb_stream * stm,
                                         cubeb_device ** const  device)
 {
 #if TARGET_OS_IPHONE
   //TODO
--- a/media/libcubeb/src/cubeb_jack.cpp
+++ b/media/libcubeb/src/cubeb_jack.cpp
@@ -41,17 +41,19 @@
   X(jack_get_buffer_size)                       \
   X(jack_port_get_buffer)                       \
   X(jack_port_name)                             \
   X(jack_port_register)                         \
   X(jack_port_unregister)                       \
   X(jack_port_get_latency_range)                \
   X(jack_set_process_callback)                  \
   X(jack_set_xrun_callback)                     \
-  X(jack_set_graph_order_callback)
+  X(jack_set_graph_order_callback)              \
+  X(jack_set_error_function)                    \
+  X(jack_set_info_function)
 
 #define IMPORT_FUNC(x) static decltype(x) * api_##x;
 JACK_API_VISIT(IMPORT_FUNC);
 
 static const int MAX_STREAMS = 16;
 static const int MAX_CHANNELS  = 8;
 static const int FIFO_SIZE = 4096 * sizeof(float);
 
@@ -278,18 +280,16 @@ cbjack_xrun_callback(void * arg)
   return 0;
 }
 
 static int
 cbjack_graph_order_callback(void * arg)
 {
   cubeb * ctx = (cubeb *)arg;
   int i;
-  uint32_t rate;
-
   jack_latency_range_t latency_range;
   jack_nframes_t port_latency, max_latency = 0;
 
   for (int j = 0; j < MAX_STREAMS; j++) {
     cubeb_stream *stm = &ctx->streams[j];
 
     if (!stm->in_use)
       continue;
@@ -559,16 +559,21 @@ cbjack_interleave_capture(cubeb_stream *
   if (format_mismatch) {
     float_to_s16ne(stream->context->in_resampled_interleaved_buffer_s16ne, in_buffer, nframes * stream->in_params.channels);
   } else {
     memset(stream->context->in_resampled_interleaved_buffer_float, 0, (FIFO_SIZE * MAX_CHANNELS * 3) * sizeof(float));
     memcpy(stream->context->in_resampled_interleaved_buffer_float, in_buffer, (FIFO_SIZE * MAX_CHANNELS * 2) * sizeof(float));
   }
 }
 
+static void
+silent_jack_error_callback(char const * /*msg*/)
+{
+}
+
 /*static*/ int
 jack_init (cubeb ** context, char const * context_name)
 {
   int r;
 
   *context = NULL;
 
   cubeb * ctx = (cubeb *)calloc(1, sizeof(*ctx));
@@ -577,16 +582,19 @@ jack_init (cubeb ** context, char const 
   }
 
   r = load_jack_lib(ctx);
   if (r != 0) {
     cbjack_destroy(ctx);
     return CUBEB_ERROR;
   }
 
+  api_jack_set_error_function(silent_jack_error_callback);
+  api_jack_set_info_function(silent_jack_error_callback);
+
   ctx->ops = &cbjack_ops;
 
   ctx->mutex = PTHREAD_MUTEX_INITIALIZER;
   for (r = 0; r < MAX_STREAMS; r++) {
     ctx->streams[r].mutex = PTHREAD_MUTEX_INITIALIZER;
   }
 
   const char * jack_client_name = "cubeb";
@@ -618,37 +626,37 @@ jack_init (cubeb ** context, char const 
 
   ctx->active = true;
   *context = ctx;
 
   return CUBEB_OK;
 }
 
 static char const *
-cbjack_get_backend_id(cubeb * context)
+cbjack_get_backend_id(cubeb * /*context*/)
 {
   return "jack";
 }
 
 static int
-cbjack_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
+cbjack_get_max_channel_count(cubeb * /*ctx*/, uint32_t * max_channels)
 {
   *max_channels = MAX_CHANNELS;
   return CUBEB_OK;
 }
 
 static int
 cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_ms)
 {
   *latency_ms = stm->context->jack_latency;
   return CUBEB_OK;
 }
 
 static int
-cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms)
+cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params /*params*/, uint32_t * latency_ms)
 {
   *latency_ms = ctx->jack_latency;
   return CUBEB_OK;
 }
 
 static int
 cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
 {
@@ -698,17 +706,17 @@ context_alloc_stream(cubeb * context, ch
 }
 
 static int
 cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
                    cubeb_devid input_device,
                    cubeb_stream_params * input_stream_params,
                    cubeb_devid output_device,
                    cubeb_stream_params * output_stream_params,
-                   unsigned int latency_frames,
+                   unsigned int /*latency_frames*/,
                    cubeb_data_callback data_callback,
                    cubeb_state_callback state_callback,
                    void * user_ptr)
 {
   int stream_actual_rate = 0;
   int jack_rate = api_jack_get_sample_rate(context->jack_client);
 
   if (output_stream_params
@@ -720,16 +728,19 @@ cbjack_stream_init(cubeb * context, cube
 
   if (input_stream_params
      && (input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE &&
          input_stream_params->format != CUBEB_SAMPLE_S16NE)
      ) {
     return CUBEB_ERROR_INVALID_FORMAT;
   }
 
+  if (input_device || output_device)
+    return CUBEB_ERROR_NOT_SUPPORTED;
+
   *stream = NULL;
 
   // Find a free stream.
   pthread_mutex_lock(&context->mutex);
   cubeb_stream * stm = context_alloc_stream(context, stream_name);
 
   // No free stream?
   if (stm == NULL) {
@@ -951,17 +962,17 @@ cbjack_stream_get_current_device(cubeb_s
     (*device)->input_name = strdup(empty);
     (*device)->output_name = strdup(j_out);
   }
 
   return CUBEB_OK;
 }
 
 static int
-cbjack_stream_device_destroy(cubeb_stream * stream,
+cbjack_stream_device_destroy(cubeb_stream * /*stream*/,
                              cubeb_device * device)
 {
   if (device->input_name)
     free(device->input_name);
   if (device->output_name)
     free(device->output_name);
   free(device);
   return CUBEB_OK;
--- a/media/libcubeb/src/cubeb_resampler.cpp
+++ b/media/libcubeb/src/cubeb_resampler.cpp
@@ -145,17 +145,17 @@ cubeb_resampler_speex<T, InputProcessor,
   * callback, drain the processors. */
   return output_processor->output(output_buffer, output_frames_needed);
 }
 
 template<typename T, typename InputProcessor, typename OutputProcessor>
 long
 cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
 ::fill_internal_input(T * input_buffer, long * input_frames_count,
-                      T * output_buffer, long output_frames_needed)
+                      T * output_buffer, long /*output_frames_needed*/)
 {
   assert(input_buffer && input_frames_count && *input_frames_count &&
          !output_buffer);
 
   /* The input data, after eventual resampling. This is passed to the callback. */
   T * resampled_input = nullptr;
   uint32_t resampled_frame_count = input_processor->output_for_input(*input_frames_count);
 
--- a/media/libcubeb/src/cubeb_utils_unix.h
+++ b/media/libcubeb/src/cubeb_utils_unix.h
@@ -15,17 +15,21 @@
 /* This wraps a critical section to track the owner in debug mode. */
 class owned_critical_section
 {
 public:
   owned_critical_section()
   {
     pthread_mutexattr_t attr;
     pthread_mutexattr_init(&attr);
-    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+#ifdef DEBUG
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+#else
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
+#endif
 
 #ifdef DEBUG
     int r =
 #endif
     pthread_mutex_init(&mutex, &attr);
 #ifdef DEBUG
     assert(r == 0);
 #endif
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@@ -755,18 +755,20 @@ refill_callback_output(cubeb_stream * st
     return true;
   }
 
   long got = refill(stm,
                     nullptr,
                     0,
                     output_buffer,
                     output_frames);
+  XASSERT(got >= 0);
+  XASSERT(got == output_frames || stm->draining);
 
-  hr = stm->render_client->ReleaseBuffer(output_frames, 0);
+  hr = stm->render_client->ReleaseBuffer(got, 0);
   if (FAILED(hr)) {
     LOG("failed to release buffer: %x\n", hr);
     return false;
   }
 
   return got == output_frames || stm->draining;
 }
 
@@ -1017,17 +1019,17 @@ current_stream_delay(cubeb_stream * stm)
   if (FAILED(hr)) {
     LOG("GetPosition failed: %x\n", hr);
     return 0;
   }
 
   double cur_pos = static_cast<double>(pos) / freq;
   double max_pos = static_cast<double>(stm->frames_written)  / stm->output_mix_params.rate;
   double delay = max_pos - cur_pos;
-  XASSERT(delay >= 0 || stm->draining);
+  XASSERT(delay >= 0);
 
   return delay;
 }
 
 int
 stream_set_volume(cubeb_stream * stm, float volume)
 {
   stm->stream_reset_lock.assert_current_thread_owns();
--- a/media/libcubeb/src/cubeb_winmm.c
+++ b/media/libcubeb/src/cubeb_winmm.c
@@ -305,16 +305,21 @@ static void winmm_destroy(cubeb * ctx);
 /*static*/ int
 winmm_init(cubeb ** context, char const * context_name)
 {
   cubeb * ctx;
 
   XASSERT(context);
   *context = NULL;
 
+  /* Don't initialize a context if there are no devices available. */
+  if (waveOutGetNumDevs() == 0) {
+    return CUBEB_ERROR;
+  }
+
   ctx = calloc(1, sizeof(*ctx));
   XASSERT(ctx);
 
   ctx->ops = &winmm_ops;
 
   ctx->work = _aligned_malloc(sizeof(*ctx->work), MEMORY_ALLOCATION_ALIGNMENT);
   XASSERT(ctx->work);
   InitializeSListHead(ctx->work);
@@ -528,33 +533,42 @@ winmm_stream_init(cubeb * context, cubeb
   *stream = stm;
 
   return CUBEB_OK;
 }
 
 static void
 winmm_stream_destroy(cubeb_stream * stm)
 {
-  DWORD r;
   int i;
-  int enqueued;
 
   if (stm->waveout) {
+    MMTIME time;
+    MMRESULT r;
+    int device_valid;
+    int enqueued;
+
     EnterCriticalSection(&stm->lock);
     stm->shutdown = 1;
 
     waveOutReset(stm->waveout);
 
+    /* Don't need this value, we just want the result to detect invalid
+       handle/no device errors than waveOutReset doesn't seem to report. */
+    time.wType = TIME_SAMPLES;
+    r = waveOutGetPosition(stm->waveout, &time, sizeof(time));
+    device_valid = !(r == MMSYSERR_INVALHANDLE || r == MMSYSERR_NODRIVER);
+
     enqueued = NBUFS - stm->free_buffers;
     LeaveCriticalSection(&stm->lock);
 
     /* Wait for all blocks to complete. */
-    while (enqueued > 0) {
-      r = WaitForSingleObject(stm->event, INFINITE);
-      XASSERT(r == WAIT_OBJECT_0);
+    while (device_valid && enqueued > 0) {
+      DWORD rv = WaitForSingleObject(stm->event, INFINITE);
+      XASSERT(rv == WAIT_OBJECT_0);
 
       EnterCriticalSection(&stm->lock);
       enqueued = NBUFS - stm->free_buffers;
       LeaveCriticalSection(&stm->lock);
     }
 
     EnterCriticalSection(&stm->lock);
 
--- a/media/libcubeb/tests/test_audio.cpp
+++ b/media/libcubeb/tests/test_audio.cpp
@@ -68,17 +68,17 @@ void synth_run_float(synth_state* synth,
     float phase_inc = 2.0 * M_PI * freq / synth->sample_rate;
     for(long n=0;n < nframes;++n) {
       audiobuffer[n*synth->num_channels+c] = sin(synth->phase[c]) * VOLUME;
       synth->phase[c] += phase_inc;
     }
   }
 }
 
-long data_cb_float(cubeb_stream *stream, void *user, const void * inputbuffer, void *outputbuffer, long nframes)
+long data_cb_float(cubeb_stream * /*stream*/, void * user, const void * /*inputbuffer*/, void * outputbuffer, long nframes)
 {
   synth_state *synth = (synth_state *)user;
   synth_run_float(synth, (float*)outputbuffer, nframes);
   return nframes;
 }
 
 void synth_run_16bit(synth_state* synth, short* audiobuffer, long nframes)
 {
@@ -87,24 +87,24 @@ void synth_run_16bit(synth_state* synth,
     float phase_inc = 2.0 * M_PI * freq / synth->sample_rate;
     for(long n=0;n < nframes;++n) {
       audiobuffer[n*synth->num_channels+c] = sin(synth->phase[c]) * VOLUME * 32767.0f;
       synth->phase[c] += phase_inc;
     }
   }
 }
 
-long data_cb_short(cubeb_stream *stream, void *user, const void * inputbuffer, void *outputbuffer, long nframes)
+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(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);
@@ -275,17 +275,17 @@ void run_channel_rate_test()
       fprintf(stderr, "--------------------------\n");
       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[])
+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();
--- a/media/libcubeb/tests/test_duplex.cpp
+++ b/media/libcubeb/tests/test_duplex.cpp
@@ -33,17 +33,17 @@
 
 struct user_state
 {
   bool seen_noise;
 };
 
 
 
-long data_cb(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 * 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;
@@ -65,17 +65,17 @@ long data_cb(cubeb_stream *stream, void 
     output_index += 2;
   }
 
   u->seen_noise |= seen_noise;
 
   return nframes;
 }
 
-void state_cb(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:
@@ -84,17 +84,17 @@ void state_cb(cubeb_stream *stream, void
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-int main(int argc, char *argv[])
+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;
--- a/media/libcubeb/tests/test_latency.cpp
+++ b/media/libcubeb/tests/test_latency.cpp
@@ -6,17 +6,17 @@
 #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[])
+int main(int /*argc*/, char * /*argv*/[])
 {
 #ifdef CUBEB_GECKO_BUILD
   ScopedXPCOM xpcom("test_latency");
 #endif
 
   cubeb * ctx = NULL;
   int r;
   uint32_t max_channels;
--- a/media/libcubeb/tests/test_record.cpp
+++ b/media/libcubeb/tests/test_record.cpp
@@ -28,17 +28,17 @@
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #endif
 
 struct user_state
 {
   bool seen_noise;
 };
 
-long data_cb(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 * u = reinterpret_cast<user_state*>(user);
 #if STREAM_FORMAT != CUBEB_SAMPLE_FLOAT32LE
   short *b = (short *)inputbuffer;
 #else
   float *b = (float *)inputbuffer;
 #endif
 
@@ -53,17 +53,17 @@ long data_cb(cubeb_stream *stream, void 
     }
   }
 
   u->seen_noise |= seen_noise;
 
   return nframes;
 }
 
-void state_cb(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:
@@ -72,17 +72,17 @@ void state_cb(cubeb_stream *stream, void
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-int main(int argc, char *argv[])
+int main(int /*argc*/, char * /*argv*/[])
 {
 #ifdef CUBEB_GECKO_BUILD
   ScopedXPCOM xpcom("test_record");
 #endif
 
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
--- a/media/libcubeb/tests/test_resampler.cpp
+++ b/media/libcubeb/tests/test_resampler.cpp
@@ -278,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(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);
@@ -459,17 +459,17 @@ void test_delay_line()
        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,
+long test_output_only_noop_data_cb(cubeb_stream * /*stm*/, void * /*user_ptr*/,
                                    const void * input_buffer,
                                    void * output_buffer, long frame_count)
 {
   assert(output_buffer);
   assert(!input_buffer);
   return frame_count;
 }
 
@@ -495,17 +495,17 @@ void test_output_only_noop()
   got = cubeb_resampler_fill(resampler, nullptr, nullptr,
                              out_buffer, out_frames);
 
   assert(got == out_frames);
 
   cubeb_resampler_destroy(resampler);
 }
 
-long test_drain_data_cb(cubeb_stream * stm, void * user_ptr,
+long test_drain_data_cb(cubeb_stream * /*stm*/, void * /*user_ptr*/,
                         const void * input_buffer,
                         void * output_buffer, long frame_count)
 {
   assert(output_buffer);
   assert(!input_buffer);
   return frame_count - 10;
 }
 
--- a/media/libcubeb/tests/test_sanity.cpp
+++ b/media/libcubeb/tests/test_sanity.cpp
@@ -31,34 +31,34 @@
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #endif
 
 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)
+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)
+test_state_callback(cubeb_stream * /*stm*/, void * /*user_ptr*/, cubeb_state /*state*/)
 {
 }
 
 static void
 test_init_destroy_context(void)
 {
   int r;
   cubeb * ctx;
@@ -489,17 +489,17 @@ test_stream_position(void)
 
   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)
+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);
@@ -508,17 +508,17 @@ test_drain_data_callback(cubeb_stream * 
 #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)
+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
@@ -603,17 +603,17 @@ int is_windows_7()
 
   return VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, condition_mask);
 #else
   return 0;
 #endif
 }
 
 int
-main(int argc, char * argv[])
+main(int /*argc*/, char * /*argv*/[])
 {
 #ifdef CUBEB_GECKO_BUILD
   ScopedXPCOM xpcom("test_sanity");
 #endif
 
   test_init_destroy_context();
   test_init_destroy_multiple_contexts();
   test_context_variables();
--- a/media/libcubeb/tests/test_tone.cpp
+++ b/media/libcubeb/tests/test_tone.cpp
@@ -29,17 +29,17 @@
 #define STREAM_FORMAT CUBEB_SAMPLE_S16LE
 #endif
 
 /* store the phase of the generated waveform */
 struct cb_user_data {
   long position;
 };
 
-long data_cb(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;
@@ -93,17 +93,17 @@ void state_cb(cubeb_stream *stream, void
     printf("stream drained\n"); break;
   default:
     printf("unknown stream state %d\n", state);
   }
 
   return;
 }
 
-int main(int argc, char *argv[])
+int main(int /*argc*/, char * /*argv*/[])
 {
 #ifdef CUBEB_GECKO_BUILD
   ScopedXPCOM xpcom("test_tone");
 #endif
 
   cubeb *ctx;
   cubeb_stream *stream;
   cubeb_stream_params params;
--- a/media/libcubeb/update.sh
+++ b/media/libcubeb/update.sh
@@ -52,10 +52,8 @@ if [ -n "$rev" ]; then
     echo "WARNING: updating from a dirty git repository."
   fi
   sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\}\./$version./" README_MOZILLA
   rm README_MOZILLA.bak
 else
   echo "Remember to update README_MOZILLA with the version details."
 fi
 
-patch -p3 < bug1278612.patch
-