示例#1
0
static int
stream_update_timing_info(cubeb_stream * stm)
{
  int r = -1;
  pa_operation * o = NULL;
  if (stm->output_stream) {
    o = WRAP(pa_stream_update_timing_info)(stm->output_stream, stream_success_callback, stm);
    if (o) {
      r = operation_wait(stm->context, stm->output_stream, o);
      WRAP(pa_operation_unref)(o);
    }
    if (r != 0) {
      return r;
    }
  }

  if (stm->input_stream) {
    o = WRAP(pa_stream_update_timing_info)(stm->input_stream, stream_success_callback, stm);
    if (o) {
      r = operation_wait(stm->context, stm->input_stream, o);
      WRAP(pa_operation_unref)(o);
    }
  }

  return r;
}
示例#2
0
static int
pulse_enumerate_devices(cubeb * context, cubeb_device_type type,
                        cubeb_device_collection ** collection)
{
  pulse_dev_list_data user_data = { NULL, NULL, NULL, 0, 0, context };
  pa_operation * o;
  uint32_t i;

  WRAP(pa_threaded_mainloop_lock)(context->mainloop);

  o = WRAP(pa_context_get_server_info)(context->context,
      pulse_server_info_cb, &user_data);
  if (o) {
    operation_wait(context, NULL, o);
    WRAP(pa_operation_unref)(o);
  }

  if (type & CUBEB_DEVICE_TYPE_OUTPUT) {
    o = WRAP(pa_context_get_sink_info_list)(context->context,
        pulse_sink_info_cb, &user_data);
    if (o) {
      operation_wait(context, NULL, o);
      WRAP(pa_operation_unref)(o);
    }
  }

  if (type & CUBEB_DEVICE_TYPE_INPUT) {
    o = WRAP(pa_context_get_source_info_list)(context->context,
        pulse_source_info_cb, &user_data);
    if (o) {
      operation_wait(context, NULL, o);
      WRAP(pa_operation_unref)(o);
    }
  }

  WRAP(pa_threaded_mainloop_unlock)(context->mainloop);

  *collection = malloc(sizeof(cubeb_device_collection) +
      sizeof(cubeb_device_info *) * (user_data.count > 0 ? user_data.count - 1 : 0));
  (*collection)->count = user_data.count;
  for (i = 0; i < user_data.count; i++)
    (*collection)->device[i] = user_data.devinfo[i];

  free(user_data.default_sink_name);
  free(user_data.default_source_name);
  free(user_data.devinfo);
  return CUBEB_OK;
}
示例#3
0
static void
pulse_destroy(cubeb * ctx)
{
  pa_operation * o;

  if (ctx->context) {
    WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
    o = WRAP(pa_context_drain)(ctx->context, context_notify_callback, ctx);
    if (o) {
      operation_wait(ctx, NULL, o);
      WRAP(pa_operation_unref)(o);
    }
    WRAP(pa_context_set_state_callback)(ctx->context, NULL, NULL);
    WRAP(pa_context_disconnect)(ctx->context);
    WRAP(pa_context_unref)(ctx->context);
    WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
  }

  if (ctx->mainloop) {
    WRAP(pa_threaded_mainloop_stop)(ctx->mainloop);
    WRAP(pa_threaded_mainloop_free)(ctx->mainloop);
  }

  if (ctx->libpulse) {
    dlclose(ctx->libpulse);
  }
  if (ctx->default_sink_info) {
    free(ctx->default_sink_info);
  }
  free(ctx);
}
示例#4
0
int
pulse_stream_set_volume(cubeb_stream * stm, float volume)
{
  uint32_t index;
  pa_operation * op;
  pa_volume_t vol;
  pa_cvolume cvol;
  const pa_sample_spec * ss;

  WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);

  ss = WRAP(pa_stream_get_sample_spec)(stm->stream);

  vol = WRAP(pa_sw_volume_from_linear)(volume);
  WRAP(pa_cvolume_set)(&cvol, ss->channels, vol);

  index = WRAP(pa_stream_get_index)(stm->stream);

  op = WRAP(pa_context_set_sink_input_volume)(stm->context->context,
                                              index, &cvol, volume_success,
                                              stm);
  if (op) {
    operation_wait(stm->context, stm->stream, op);
    WRAP(pa_operation_unref)(op);
  }
  WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);

  return CUBEB_OK;
}
示例#5
0
static void
cork_io_stream(cubeb_stream * stm, pa_stream * io_stream, enum cork_state state)
{
  pa_operation * o;
  if (!io_stream) {
    return;
  }
  o = WRAP(pa_stream_cork)(io_stream, state & CORK, stream_success_callback, stm);
  if (o) {
    operation_wait(stm->context, io_stream, o);
    WRAP(pa_operation_unref)(o);
  }
}
示例#6
0
static void
pulse_context_destroy(cubeb * ctx)
{
  pa_operation * o;

  WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
  o = WRAP(pa_context_drain)(ctx->context, context_notify_callback, ctx);
  if (o) {
    operation_wait(ctx, NULL, o);
    WRAP(pa_operation_unref)(o);
  }
  WRAP(pa_context_set_state_callback)(ctx->context, NULL, NULL);
  WRAP(pa_context_disconnect)(ctx->context);
  WRAP(pa_context_unref)(ctx->context);
  WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
}
示例#7
0
static void
stream_cork(cubeb_stream * stm, enum cork_state state)
{
  pa_operation * o;

  pa_threaded_mainloop_lock(stm->context->mainloop);
  o = pa_stream_cork(stm->stream, state & CORK, stream_success_callback, stm->context->mainloop);
  operation_wait(stm->context, o);
  pa_operation_unref(o);
  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);
  }
}
示例#8
0
int
pulse_stream_set_volume(cubeb_stream * stm, float volume)
{
  uint32_t index;
  pa_operation * op;
  pa_volume_t vol;
  pa_cvolume cvol;
  const pa_sample_spec * ss;

  if (!stm->output_stream) {
    return CUBEB_ERROR;
  }

  WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);

  while (!stm->context->default_sink_info) {
    WRAP(pa_threaded_mainloop_wait)(stm->context->mainloop);
  }

  /* if the pulse daemon is configured to use flat volumes,
   * apply our own gain instead of changing the input volume on the sink. */
  if (stm->context->default_sink_info->flags & PA_SINK_FLAT_VOLUME) {
    stm->volume = volume;
  } else {
    ss = WRAP(pa_stream_get_sample_spec)(stm->output_stream);

    vol = WRAP(pa_sw_volume_from_linear)(volume);
    WRAP(pa_cvolume_set)(&cvol, ss->channels, vol);

    index = WRAP(pa_stream_get_index)(stm->output_stream);

    op = WRAP(pa_context_set_sink_input_volume)(stm->context->context,
                                                index, &cvol, volume_success,
                                                stm);
    if (op) {
      operation_wait(stm->context, stm->output_stream, op);
      WRAP(pa_operation_unref)(op);
    }
  }

  WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);

  return CUBEB_OK;
}
示例#9
0
int pulse_register_device_collection_changed(cubeb * context,
                                             cubeb_device_type devtype,
                                             cubeb_device_collection_changed_callback collection_changed_callback,
                                             void * user_ptr)
{
  context->collection_changed_callback = collection_changed_callback;
  context->collection_changed_user_ptr = user_ptr;

  WRAP(pa_threaded_mainloop_lock)(context->mainloop);

  pa_subscription_mask_t mask;
  if (context->collection_changed_callback == NULL) {
    // Unregister subscription
    WRAP(pa_context_set_subscribe_callback)(context->context, NULL, NULL);
    mask = PA_SUBSCRIPTION_MASK_NULL;
  } else {
    WRAP(pa_context_set_subscribe_callback)(context->context, pulse_subscribe_callback, context);
    if (devtype == CUBEB_DEVICE_TYPE_INPUT)
      mask = PA_SUBSCRIPTION_MASK_SOURCE;
    else if (devtype == CUBEB_DEVICE_TYPE_OUTPUT)
      mask = PA_SUBSCRIPTION_MASK_SINK;
    else
      mask = PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE;
  }

  pa_operation * o;
  o = WRAP(pa_context_subscribe)(context->context, mask, subscribe_success, context);
  if (o == NULL) {
    LOG("Context subscribe failed\n");
    return CUBEB_ERROR;
  }
  operation_wait(context, NULL, o);
  WRAP(pa_operation_unref)(o);

  WRAP(pa_threaded_mainloop_unlock)(context->mainloop);

  return CUBEB_OK;
}
示例#10
0
void
cubeb_destroy(cubeb * ctx)
{
  pa_operation * o;

  if (ctx->context) {
    pa_threaded_mainloop_lock(ctx->mainloop);
    o = pa_context_drain(ctx->context, context_notify_callback, ctx->mainloop);
    if (o) {
      operation_wait(ctx, o);
      pa_operation_unref(o);
    }
    pa_context_disconnect(ctx->context);
    pa_context_unref(ctx->context);
    pa_threaded_mainloop_unlock(ctx->mainloop);
  }

  if (ctx->mainloop) {
    pa_threaded_mainloop_stop(ctx->mainloop);
    pa_threaded_mainloop_free(ctx->mainloop);
  }

  free(ctx);
}
示例#11
0
static int
pulse_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
                  cubeb_stream_params stream_params, unsigned int latency,
                  cubeb_data_callback data_callback, cubeb_state_callback state_callback,
                  void * user_ptr)
{
  pa_sample_spec ss;
  cubeb_stream * stm;
  pa_operation * o;
  pa_buffer_attr battr;
  pa_channel_map map;
  int r;

  assert(context);

  *stream = NULL;

  switch (stream_params.format) {
  case CUBEB_SAMPLE_S16LE:
    ss.format = PA_SAMPLE_S16LE;
    break;
  case CUBEB_SAMPLE_S16BE:
    ss.format = PA_SAMPLE_S16BE;
    break;
  case CUBEB_SAMPLE_FLOAT32LE:
    ss.format = PA_SAMPLE_FLOAT32LE;
    break;
  case CUBEB_SAMPLE_FLOAT32BE:
    ss.format = PA_SAMPLE_FLOAT32BE;
    break;
  default:
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  ss.rate = stream_params.rate;
  ss.channels = stream_params.channels;

  /* XXX check that this does the right thing for Vorbis and WaveEx */
  WRAP(pa_channel_map_init_auto)(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT);

  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->sample_spec = ss;

  battr.maxlength = -1;
  battr.tlength = WRAP(pa_usec_to_bytes)(latency * PA_USEC_PER_MSEC, &stm->sample_spec);
  battr.prebuf = -1;
  battr.minreq = battr.tlength / 4;
  battr.fragsize = -1;

  WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
  stm->stream = WRAP(pa_stream_new)(stm->context->context, stream_name, &ss, &map);
  WRAP(pa_stream_set_state_callback)(stm->stream, stream_state_callback, stm);
  WRAP(pa_stream_set_write_callback)(stm->stream, stream_request_callback, stm);
  WRAP(pa_stream_connect_playback)(stm->stream, NULL, &battr,
                             PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
                             PA_STREAM_START_CORKED,
                             NULL, NULL);

  r = wait_until_stream_ready(stm);
  if (r == 0) {
    /* force a timing update now, otherwise timing info does not become valid
       until some point after initialization has completed. */
    o = WRAP(pa_stream_update_timing_info)(stm->stream, stream_success_callback, stm);
    if (o) {
      r = operation_wait(stm->context, stm->stream, o);
      WRAP(pa_operation_unref)(o);
    }
  }
  WRAP(pa_threaded_mainloop_unlock)(stm->context->mainloop);

  if (r != 0) {
    pulse_stream_destroy(stm);
    return CUBEB_ERROR;
  }

  *stream = stm;

  return CUBEB_OK;
}