Ejemplo n.º 1
0
/*static*/ int
jack_init (cubeb ** context, char const * context_name)
{
  int r;

  *context = NULL;

  cubeb * ctx = (cubeb *)calloc(1, sizeof(*ctx));
  if (ctx == NULL) {
    return CUBEB_ERROR;
  }

  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";
  if (context_name)
    jack_client_name = context_name;

  ctx->jack_client = api_jack_client_open(jack_client_name,
                                          JackNoStartServer,
                                          NULL);

  if (ctx->jack_client == NULL) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  ctx->jack_xruns = 0;

  api_jack_set_process_callback (ctx->jack_client, cbjack_process, ctx);
  api_jack_set_xrun_callback (ctx->jack_client, cbjack_xrun_callback, ctx);
  api_jack_set_graph_order_callback (ctx->jack_client, cbjack_graph_order_callback, ctx);

  if (api_jack_activate (ctx->jack_client)) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  ctx->jack_sample_rate = api_jack_get_sample_rate(ctx->jack_client);
  ctx->jack_latency = 128 * 1000 / ctx->jack_sample_rate;

  ctx->active = true;
  *context = ctx;

  return CUBEB_OK;
}
Ejemplo n.º 2
0
static int
cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
  if (!ctx->jack_client) {
    jack_client_t * testclient = api_jack_client_open("test-samplerate",
                                                 JackNoStartServer,
                                                 NULL);
    if (!testclient) {
      return CUBEB_ERROR;
    }

    *rate = api_jack_get_sample_rate(testclient);
    api_jack_client_close(testclient);

  } else {
    *rate = api_jack_get_sample_rate(ctx->jack_client);
  }
  return CUBEB_OK;
}
Ejemplo n.º 3
0
/*static*/ int
jack_init (cubeb ** context, char const * context_name)
{
  int r;

  if (context == NULL) {
    return CUBEB_ERROR_INVALID_PARAMETER;
  }

  *context = NULL;

  cubeb *ctx = (cubeb*)calloc(1, sizeof(*ctx));
  if (ctx == NULL) {
    return CUBEB_ERROR;
  }

  r = load_jack_lib(ctx);
  if (r != 0) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  r = pthread_mutex_init(&ctx->mutex, NULL);
  if (r != 0) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  ctx->ops = &cbjack_ops;

  const char* jack_client_name = "cubeb";
  if (context_name)
    jack_client_name = context_name;

  ctx->jack_client = api_jack_client_open(jack_client_name,
                                          JackNoStartServer,
                                          NULL);

  if (ctx->jack_client == NULL) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  ctx->jack_sample_rate = api_jack_get_sample_rate(ctx->jack_client);

  api_jack_set_process_callback (ctx->jack_client, cbjack_process, ctx);

  if (api_jack_activate (ctx->jack_client)) {
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  for (int s = 0; s < MAX_STREAMS; s++) {
    for (int c = 0; c < MAX_CHANNELS; c++) {
      ctx->streams[s].ringbuffer[c] = api_jack_ringbuffer_create(FIFO_SIZE);
      if (!ctx->streams[s].ringbuffer[c]) {
        cbjack_destroy(ctx);
        return CUBEB_ERROR;
      }
    }
  }

  ctx->active = true;
  r = pthread_create (&ctx->stream_refill_thread, NULL, stream_refill_thread, (void *)ctx);
  if (r != 0) {
    ctx->stream_refill_thread = 0;
    cbjack_destroy(ctx);
    return CUBEB_ERROR;
  }

  *context = ctx;

  return CUBEB_OK;
}
Ejemplo n.º 4
0
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,
                   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
     && (output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE &&
         output_stream_params->format != CUBEB_SAMPLE_S16NE)
     ) {
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  if (input_stream_params
     && (input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE &&
         input_stream_params->format != CUBEB_SAMPLE_S16NE)
     ) {
    return CUBEB_ERROR_INVALID_FORMAT;
  }

  *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) {
    pthread_mutex_unlock(&context->mutex);
    return CUBEB_ERROR;
  }

  // unlock context mutex
  pthread_mutex_unlock(&context->mutex);

  // Lock active stream
  pthread_mutex_lock(&stm->mutex);

  stm->ports_ready = false;
  stm->user_ptr = user_ptr;
  stm->context = context;
  stm->devs = NONE;
  if (output_stream_params && !input_stream_params) {
    stm->out_params = *output_stream_params;
    stream_actual_rate = stm->out_params.rate;
    stm->out_params.rate = jack_rate;
    stm->devs = OUT_ONLY;
    if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) {
      context->output_bytes_per_frame = sizeof(float);
    } else {
      context->output_bytes_per_frame = sizeof(short);
    }
  }
  if (input_stream_params && output_stream_params) {
    stm->in_params = *input_stream_params;
    stm->out_params = *output_stream_params;
    stream_actual_rate = stm->out_params.rate;
    stm->in_params.rate = jack_rate;
    stm->out_params.rate = jack_rate;
    stm->devs = DUPLEX;
    if (stm->out_params.format == CUBEB_SAMPLE_FLOAT32NE) {
      context->output_bytes_per_frame = sizeof(float);
      stm->in_params.format = CUBEB_SAMPLE_FLOAT32NE;
    } else {
      context->output_bytes_per_frame = sizeof(short);
      stm->in_params.format = CUBEB_SAMPLE_S16NE;
    }
  } else if (input_stream_params && !output_stream_params) {
    stm->in_params = *input_stream_params;
    stream_actual_rate = stm->in_params.rate;
    stm->in_params.rate = jack_rate;
    stm->devs = IN_ONLY;
    if (stm->in_params.format == CUBEB_SAMPLE_FLOAT32NE) {
      context->output_bytes_per_frame = sizeof(float);
    } else {
      context->output_bytes_per_frame = sizeof(short);
    }
  }

  stm->ratio = (float)stream_actual_rate / (float)jack_rate;

  stm->data_callback = data_callback;
  stm->state_callback = state_callback;
  stm->position = 0;
  stm->volume = 1.0f;
  context->jack_buffer_size = api_jack_get_buffer_size(context->jack_client);
  context->fragment_size = context->jack_buffer_size;

  if (stm->devs == NONE) {
    pthread_mutex_unlock(&stm->mutex);
    return CUBEB_ERROR;
  }

  stm->resampler = NULL;

  if (stm->devs == DUPLEX) {
    stm->resampler = cubeb_resampler_create(stm,
                                          &stm->in_params,
                                          &stm->out_params,
                                          stream_actual_rate,
                                          stm->data_callback,
                                          stm->user_ptr,
                                          CUBEB_RESAMPLER_QUALITY_DESKTOP);
  } else if (stm->devs == IN_ONLY) {
    stm->resampler = cubeb_resampler_create(stm,
                                          &stm->in_params,
                                          nullptr,
                                          stream_actual_rate,
                                          stm->data_callback,
                                          stm->user_ptr,
                                          CUBEB_RESAMPLER_QUALITY_DESKTOP);
  } else if (stm->devs == OUT_ONLY) {
    stm->resampler = cubeb_resampler_create(stm,
                                          nullptr,
                                          &stm->out_params,
                                          stream_actual_rate,
                                          stm->data_callback,
                                          stm->user_ptr,
                                          CUBEB_RESAMPLER_QUALITY_DESKTOP);
  }

  if (!stm->resampler) {
    stm->in_use = false;
    pthread_mutex_unlock(&stm->mutex);
    return CUBEB_ERROR;
  }

  if (stm->devs == DUPLEX || stm->devs == OUT_ONLY) {
    for (unsigned int c = 0; c < stm->out_params.channels; c++) {
      char portname[256];
      snprintf(portname, 255, "%s_out_%d", stm->stream_name, c);
      stm->output_ports[c] = api_jack_port_register(stm->context->jack_client,
                                                    portname,
                                                    JACK_DEFAULT_AUDIO_TYPE,
                                                    JackPortIsOutput,
                                                    0);
    }
  }

  if (stm->devs == DUPLEX || stm->devs == IN_ONLY) {
    for (unsigned int c = 0; c < stm->in_params.channels; c++) {
      char portname[256];
      snprintf(portname, 255, "%s_in_%d", stm->stream_name, c);
      stm->input_ports[c] = api_jack_port_register(stm->context->jack_client,
                                                    portname,
                                                    JACK_DEFAULT_AUDIO_TYPE,
                                                    JackPortIsInput,
                                                    0);
    }
  }

  cbjack_connect_ports(stm);

  *stream = stm;

  stm->ports_ready = true;
  stm->pause = true;
  pthread_mutex_unlock(&stm->mutex);

  return CUBEB_OK;
}