Bug 1286041 - Update cubeb library on commit 2f3b9eb. r=kinetik
☠☠ backed out by 73a38f53b9b0 ☠ ☠
authorAlex Chronopoulos <achronop@gmail.com>
Tue, 06 Sep 2016 13:40:43 +0200
changeset 354111 42eb493a3791e810e5f248f8d0db20fdb680727a
parent 354110 232069c626269a71a3c2c0cd5d9cc3d4f2327338
child 354112 664a9cffbf1a07d1382c305aaa4c7dc3c339f0d9
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1286041
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1286041 - Update cubeb library on commit 2f3b9eb. r=kinetik MozReview-Commit-ID: EwVDPekHPsg
media/libcubeb/README_MOZILLA
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_pulse.c
media/libcubeb/src/cubeb_resampler.cpp
media/libcubeb/src/cubeb_utils_unix.h
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
--- 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 2f3b9eb51dcb11dbbe61df9a00219029f6dea90c.
--- 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
@@ -449,8 +449,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
@@ -48,16 +49,22 @@
 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(...)
@@ -175,17 +182,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 +411,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) {
@@ -899,79 +907,63 @@ audiounit_create_unit(AudioUnit * unit,
 {
   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 == NULL && !is_input;
-  if (use_default_output) {
-    desc.componentSubType = kAudioUnitSubType_DefaultOutput;
-  } else {
-    desc.componentSubType = kAudioUnitSubType_HALOutput;
-  }
-#endif
+  desc.componentSubType = CUBEB_AUDIOUNIT_SUBTYPE;
   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;
   }
 
-  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 = 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) {
-      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;
-    }
+  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;
   }
 
   return CUBEB_OK;
 }
 
 static int
 audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
 {
@@ -1608,21 +1600,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
@@ -278,18 +278,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;
@@ -618,37 +616,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 +696,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 +718,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 +952,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_pulse.c
+++ b/media/libcubeb/src/cubeb_pulse.c
@@ -68,22 +68,24 @@
   X(pa_threaded_mainloop_start)                 \
   X(pa_threaded_mainloop_stop)                  \
   X(pa_threaded_mainloop_unlock)                \
   X(pa_threaded_mainloop_wait)                  \
   X(pa_usec_to_bytes)                           \
   X(pa_stream_set_read_callback)                \
   X(pa_stream_connect_record)                   \
   X(pa_stream_readable_size)                    \
+  X(pa_stream_writable_size)                    \
   X(pa_stream_peek)                             \
   X(pa_stream_drop)                             \
   X(pa_stream_get_buffer_attr)                  \
   X(pa_stream_get_device_name)                  \
   X(pa_context_set_subscribe_callback)          \
   X(pa_context_subscribe)                       \
+  X(pa_mainloop_api_once)                       \
 
 #define MAKE_TYPEDEF(x) static typeof(x) * cubeb_##x;
 LIBPULSE_API_VISIT(MAKE_TYPEDEF);
 #undef MAKE_TYPEDEF
 #endif
 
 //#define LOGGING_ENABLED
 #ifdef LOGGING_ENABLED
@@ -115,16 +117,17 @@ struct cubeb_stream {
   cubeb_data_callback data_callback;
   cubeb_state_callback state_callback;
   void * user_ptr;
   pa_time_event * drain_timer;
   pa_sample_spec output_sample_spec;
   pa_sample_spec input_sample_spec;
   int shutdown;
   float volume;
+  cubeb_state state;
 };
 
 const float PULSE_NO_GAIN = -1.0;
 
 enum cork_state {
   UNCORK = 0,
   CORK = 1 << 0,
   NOTIFY = 1 << 1
@@ -168,31 +171,39 @@ context_notify_callback(pa_context * c, 
 static void
 stream_success_callback(pa_stream * s, int success, void * u)
 {
   cubeb_stream * stm = u;
   WRAP(pa_threaded_mainloop_signal)(stm->context->mainloop, 0);
 }
 
 static void
+stream_state_change_callback(cubeb_stream * stm, cubeb_state s)
+{
+  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)
 {
   cubeb_stream * stm = u;
+  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;
-  stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED);
+  WRAP(pa_threaded_mainloop_signal)(stm->context->mainloop, 0);
 }
 
 static void
 stream_state_callback(pa_stream * s, void * u)
 {
   cubeb_stream * stm = u;
   if (!PA_STREAM_IS_GOOD(WRAP(pa_stream_get_state)(s))) {
-    stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
+    stream_state_change_callback(stm, CUBEB_STATE_ERROR);
   }
   WRAP(pa_threaded_mainloop_signal)(stm->context->mainloop, 0);
 }
 
 static void
 trigger_user_callback(pa_stream * s, void const * input_data, size_t nbytes, cubeb_stream * stm)
 {
   void * buffer;
@@ -281,17 +292,18 @@ read_from_input(pa_stream * s, void cons
   return readable_size;
 }
 
 static void
 stream_write_callback(pa_stream * s, size_t nbytes, void * u)
 {
   LOG("Output callback to be written buffer size %zd\n", nbytes);
   cubeb_stream * stm = u;
-  if (stm->shutdown) {
+  if (stm->shutdown ||
+      stm->state != CUBEB_STATE_STARTED) {
     return;
   }
 
   if (!stm->input_stream){
     // Output/playback only operation.
     // Write directly to output
     assert(!stm->input_stream && stm->output_stream);
     trigger_user_callback(s, NULL, nbytes, stm);
@@ -419,18 +431,18 @@ static void
 stream_cork(cubeb_stream * stm, enum cork_state state)
 {
   WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
   cork_io_stream(stm, stm->output_stream, state);
   cork_io_stream(stm, stm->input_stream, state);
   WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
 
   if (state & NOTIFY) {
-    stm->state_callback(stm, stm->user_ptr,
-                        state & CORK ? CUBEB_STATE_STOPPED : CUBEB_STATE_STARTED);
+    stream_state_change_callback(stm, state & CORK ? CUBEB_STATE_STOPPED
+                                                   : CUBEB_STATE_STARTED);
   }
 }
 
 static int
 stream_update_timing_info(cubeb_stream * stm)
 {
   int r = -1;
   pa_operation * o = NULL;
@@ -714,16 +726,18 @@ pulse_stream_init(cubeb * context,
   stm = calloc(1, sizeof(*stm));
   assert(stm);
 
   stm->context = context;
   stm->data_callback = data_callback;
   stm->state_callback = state_callback;
   stm->user_ptr = user_ptr;
   stm->volume = PULSE_NO_GAIN;
+  stm->state = -1;
+  assert(stm->shutdown == 0);
 
   WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
   if (output_stream_params) {
     r = create_pa_stream(stm, &stm->output_stream, output_stream_params, stream_name);
     if (r != CUBEB_OK) {
       WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
       pulse_stream_destroy(stm);
       return r;
@@ -825,26 +839,54 @@ pulse_stream_destroy(cubeb_stream * stm)
     WRAP(pa_stream_disconnect)(stm->input_stream);
     WRAP(pa_stream_unref)(stm->input_stream);
   }
   WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
 
   free(stm);
 }
 
+void
+pulse_defer_event_cb(pa_mainloop_api * a, void * userdata)
+{
+  cubeb_stream * stm = userdata;
+  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;
   stream_cork(stm, UNCORK | NOTIFY);
+
+  if (stm->output_stream && !stm->input_stream) {
+    /* On output only case need to manually call user cb once in order to make
+     * things roll. This is done via a defer event in order to execute it
+     * from PA server thread. */
+    WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
+    WRAP(pa_mainloop_api_once)(WRAP(pa_threaded_mainloop_get_api)(stm->context->mainloop),
+                               pulse_defer_event_cb, stm);
+    WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
+  }
+
   return CUBEB_OK;
 }
 
 static int
 pulse_stream_stop(cubeb_stream * stm)
 {
+  WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
+  stm->shutdown = 1;
+  // If draining is taking place wait to finish
+  while (stm->drain_timer) {
+    WRAP(pa_threaded_mainloop_wait)(stm->context->mainloop);
+  }
+  WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);
+
   stream_cork(stm, CORK | NOTIFY);
   return CUBEB_OK;
 }
 
 static int
 pulse_stream_get_position(cubeb_stream * stm, uint64_t * position)
 {
   int r, in_thread;
--- 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/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;