Commit b8d65507 authored by Alex Chronopoulos's avatar Alex Chronopoulos
Browse files

Bug 1286041 - Cubeb PulseAudio backend stop calling callback before stream start. r=kinetik

--HG--
extra : rebase_source : cf6f9603d9b069477be572a04b7d2e0999a72d2f
parent db8bffd0
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,4 +5,4 @@ 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 50b92089d92ca9e5d1bc222849d199cc0686867b.
+27 −5
Original line number Diff line number Diff line
@@ -11,6 +11,29 @@
#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);
@@ -55,8 +78,7 @@ struct cubeb_ops {
#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)

+7 −0
Original line number Diff line number Diff line
@@ -454,3 +454,10 @@ int cubeb_register_device_collection_changed(cubeb * context,
  return context->ops->register_device_collection_changed(context, devtype, callback, user_ptr);
}

void cubeb_crash()
{
  abort();
  *((volatile int *) NULL) = 0;
}

+36 −5
Original line number Diff line number Diff line
@@ -73,12 +73,14 @@
  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);
@@ -120,6 +122,7 @@ struct cubeb_stream {
  pa_sample_spec input_sample_spec;
  int shutdown;
  float volume;
  cubeb_state state;
};

const float PULSE_NO_GAIN = -1.0;
@@ -172,6 +175,13 @@ stream_success_callback(pa_stream * s, int success, void * 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)
{
@@ -179,7 +189,7 @@ stream_drain_callback(pa_mainloop_api * a, pa_time_event * e, struct timeval con
  /* 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);
  stream_state_change_callback(stm, CUBEB_STATE_DRAINED);
}

static void
@@ -187,7 +197,7 @@ 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);
}
@@ -286,7 +296,8 @@ 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;
  }

@@ -424,8 +435,8 @@ stream_cork(cubeb_stream * stm, enum cork_state 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);
  }
}

@@ -719,6 +730,7 @@ pulse_stream_init(cubeb * context,
  stm->state_callback = state_callback;
  stm->user_ptr = user_ptr;
  stm->volume = PULSE_NO_GAIN;
  stm->state = -1;

  WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
  if (output_stream_params) {
@@ -830,10 +842,29 @@ pulse_stream_destroy(cubeb_stream * stm)
  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)
{
  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;
}