static int op_jack_open(sample_format_t sf, const channel_position_t *cm) { sample_format = sf; if (fail) { /* jack went away so lets see if we can recover */ if (client != NULL) { op_jack_exit(); } if (op_jack_init() != OP_ERROR_SUCCESS) { return -OP_ERROR_INTERNAL; } } if (cm == NULL) { d_print("no channel_map\n"); return -OP_ERROR_NOT_SUPPORTED; } channel_map = cm; #ifdef HAVE_SAMPLERATE op_jack_reset_src(); resample_ratio = (float) jack_sample_rate / (float) sf_get_rate(sf); #else if (jack_sample_rate != sf_get_rate(sf)) { d_print("jack sample rate of %d does not match %d\n", jack_get_sample_rate(client), sf_get_rate(sf)); return -OP_ERROR_SAMPLE_FORMAT; } #endif if (sf_get_channels(sf) < CHANNELS) { d_print("%d channels not supported\n", sf_get_channels(sf)); return -OP_ERROR_SAMPLE_FORMAT; } int bits = sf_get_bits(sf); if (bits == 16) { sample_bytes = 2; read_sample = sf_get_signed(sf) ? &read_sample_le16 : &read_sample_le16u; } else if (bits == 24) { sample_bytes = 3; read_sample = sf_get_signed(sf) ? &read_sample_le24 : &read_sample_le24u; } else if (bits == 32) { sample_bytes = 4; read_sample = sf_get_signed(sf) ? &read_sample_le32 : &read_sample_le32u; } else { d_print("%d bits not supported\n", sf_get_bits(sf)); return -OP_ERROR_SAMPLE_FORMAT; } paused = false; return OP_ERROR_SUCCESS; }
/* init or resize buffers if needed */ static int op_jack_buffer_init(jack_nframes_t samples, void *arg) { if (buffer_size > samples * BUFFER_MULTIPLYER) { /* we just don't shrink buffers, since this could result * in gaps and they won't get that big anyway */ return 0; } buffer_size = samples * BUFFER_MULTIPLYER; if (buffer_size < BUFFER_SIZE_MIN) { buffer_size = BUFFER_SIZE_MIN; } d_print("new buffer size %zu\n", buffer_size); char *tmp = xmalloc(buffer_size); for (int i = 0; i < CHANNELS; i++) { jack_ringbuffer_t *new_buffer = jack_ringbuffer_create(buffer_size); if (!new_buffer) { d_print("ringbuffer alloc failed\n"); free(tmp); fail = 1; op_jack_exit(); return 1; } if (ringbuffer[i] != NULL) { size_t length = jack_ringbuffer_read_space(ringbuffer[i]); /* actualy this could both read/write less than length. * In that case, which should not happen[TM], there will * be a gap in playback. */ jack_ringbuffer_read(ringbuffer[i], tmp, length); jack_ringbuffer_write(new_buffer, tmp, length); jack_ringbuffer_free(ringbuffer[i]); } ringbuffer[i] = new_buffer; } free(tmp); return 0; }
static int op_jack_buffer_space(void) { if (fail) { op_jack_exit(); return -OP_ERROR_INTERNAL; } int bytes = jack_ringbuffer_write_space(ringbuffer[0]); for (int c = 1; c < CHANNELS; c++) { int tmp = jack_ringbuffer_write_space(ringbuffer[0]); if (bytes > tmp) { bytes = tmp; } } int frames = bytes / sizeof(jack_default_audio_sample_t); int frame_size = sf_get_frame_size(sample_format); #ifdef HAVE_SAMPLERATE return (int) ((float) (frames) / resample_ratio) * frame_size; #else return frames * frame_size; #endif }
static int op_jack_write(const char *buffer, int count) { if (fail) { op_jack_exit(); return -OP_ERROR_INTERNAL; } if (!drop_done) { return 0; } int frame_size = sf_get_frame_size(sample_format); int channels = sf_get_channels(sample_format); size_t frames = count / frame_size; /* since this is the only place where the ringbuffers get * written, available space will only grow, therefore frames_min * is safe. */ size_t frames_min = SIZE_MAX; for (int c = 0; c < CHANNELS; c++) { size_t frames_available = jack_ringbuffer_write_space(ringbuffer[c]) / sizeof(jack_default_audio_sample_t); if (frames_available < frames_min) { frames_min = frames_available; } } if (frames > frames_min) { frames = frames_min; } jack_default_audio_sample_t buf[CHANNELS][buffer_size]; /* demux and convert to float */ for (int pos = 0; pos < count; ) { int frame = pos / frame_size; for (int c = 0; c < channels; c++) { int idx = pos + c * sample_bytes; /* for now, only 2 channels and mono are supported */ if (channel_map[c] == CHANNEL_POSITION_LEFT || channel_map[c] == CHANNEL_POSITION_MONO) { buf[0][frame] = read_sample(&buffer[idx]); } else if (channel_map[c] == CHANNEL_POSITION_RIGHT || channel_map[c] == CHANNEL_POSITION_MONO) { buf[1][frame] = read_sample(&buffer[idx]); } } pos += frame_size; } #ifdef HAVE_SAMPLERATE if (resample_ratio > 1.01f || resample_ratio < 0.99) { jack_default_audio_sample_t converted[buffer_size]; SRC_DATA src_data; for (int c = 0; c < CHANNELS; c++) { src_data.data_in = buf[c]; src_data.data_out = converted; src_data.input_frames = frames; src_data.output_frames = frames_min; src_data.src_ratio = resample_ratio; src_data.end_of_input = 0; int err = src_process(src_state[c], &src_data); if (err) { d_print("libsamplerate err %s\n", src_strerror(err)); } int byte_length = src_data.output_frames_gen * sizeof(jack_default_audio_sample_t); jack_ringbuffer_write(ringbuffer[c], (const char*) converted, byte_length); } return src_data.input_frames_used * frame_size; } else { #endif int byte_length = frames * sizeof(jack_default_audio_sample_t); for (int c = 0; c < CHANNELS; c++) { jack_ringbuffer_write(ringbuffer[c], (const char*) buf[c], byte_length); } return frames * frame_size; #ifdef HAVE_SAMPLERATE } #endif }