Bug 1286041 - Update cubeb library on commit a317ba0. r=kinetik
authorAlex Chronopoulos <achronop@gmail.com>
Fri, 23 Sep 2016 19:16:17 +0300
changeset 315179 1db5e766a1ecaf1f1f501932215d717304c6fa70
parent 315178 6029a9a8b8db8c851e488c6de8b0c0876e633408
child 315180 f737abca53388fb8a00a6656d2989ece1edc590f
push id32563
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:18:33 +0000
treeherderautoland@eb840c87b5fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskinetik
bugs1286041
milestone52.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 a317ba0. r=kinetik
media/libcubeb/README_MOZILLA
media/libcubeb/src/cubeb_pulse.c
--- a/media/libcubeb/README_MOZILLA
+++ b/media/libcubeb/README_MOZILLA
@@ -1,8 +1,8 @@
 The source from this directory was copied from the cubeb 
 git repository using the update.sh script.  The only changes
 made were those applied by update.sh and the addition of
 Makefile.in build files for the Mozilla build system.
 
 The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
 
-The git commit ID used was 92b4afa6ae9f0969e77d59a8f9de9ab36acd7d7f.
+The git commit ID used was a317ba01a7b9afa0ba31b77ab9419244ebc4cf23.
--- 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;