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) { assert(!input_stream_params && "not supported."); if (input_device || output_device) { /* Device selection not yet implemented. */ return CUBEB_ERROR_DEVICE_UNAVAILABLE; } if (stream == NULL || output_stream_params == NULL) { return CUBEB_ERROR_INVALID_PARAMETER; } if (output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE && output_stream_params->format != CUBEB_SAMPLE_S16NE) { return CUBEB_ERROR_INVALID_FORMAT; } *stream = NULL; // Lock streams AutoLock lock(context->mutex); // Find a free stream. cubeb_stream * stm = context_alloc_stream(context, stream_name); // No free stream? if (stm == NULL) { return CUBEB_ERROR; } stm->user_ptr = user_ptr; stm->context = context; stm->params = *output_stream_params; stm->data_callback = data_callback; stm->state_callback = state_callback; stm->position = 0; stm->volume = 1.0f; if (stm->params.rate != stm->context->jack_sample_rate) { int resampler_error; stm->resampler = speex_resampler_init(stm->params.channels, stm->params.rate, stm->context->jack_sample_rate, 10, &resampler_error); if (resampler_error != 0) { stm->in_use = false; return CUBEB_ERROR; } } for (unsigned int c = 0; c < stm->params.channels; c++) { char portname[256]; snprintf(portname, 255, "%s_%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 (AUTO_CONNECT_JACK_PORTS) { cbjack_connect_ports(stm); } stm->ports_ready = true; *stream = stm; return CUBEB_OK; }
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; }