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; }
static int waveout_open(sample_format_t sf) { WAVEFORMATEX format; int rc, i; /* WAVEFORMATEX does not support channels > 2, waveOutWrite() wants little endian signed PCM */ if (sf_get_bigendian(sf) || !sf_get_signed(sf) || sf_get_channels(sf) > 2) { return -OP_ERROR_SAMPLE_FORMAT; } memset(&format, 0, sizeof(format)); format.cbSize = sizeof(format); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = sf_get_channels(sf); format.nSamplesPerSec = sf_get_rate(sf); format.wBitsPerSample = sf_get_bits(sf); format.nAvgBytesPerSec = sf_get_second_size(sf); format.nBlockAlign = sf_get_frame_size(sf); if ((rc = waveOutOpen(&wave_out, WAVE_MAPPER, &format, 0, 0, CALLBACK_NULL)) != MMSYSERR_NOERROR) { switch (rc) { case MMSYSERR_ALLOCATED: errno = EBUSY; return -OP_ERROR_ERRNO; case MMSYSERR_BADDEVICEID: case MMSYSERR_NODRIVER: errno = ENODEV; return -OP_ERROR_ERRNO; case MMSYSERR_NOMEM: errno = ENOMEM; return -OP_ERROR_ERRNO; case WAVERR_BADFORMAT: return -OP_ERROR_SAMPLE_FORMAT; } return -OP_ERROR_INTERNAL; } /* reset buffers */ for (i = 0; i < buffer_count; i++) { buffers[i].dwFlags = 0; } buffer_idx = 0; buffers_free = buffer_count; waveout_sf = sf; return 0; }
static int change_sf(int drop) { int old_sf = buffer_sf; CHANNEL_MAP(old_channel_map); channel_map_copy(old_channel_map, buffer_channel_map); set_buffer_sf(); if (buffer_sf != old_sf || !channel_map_equal(buffer_channel_map, old_channel_map, sf_get_channels(buffer_sf))) { /* reopen */ int rc; if (drop) op_drop(); op_close(); rc = op_open(buffer_sf, buffer_channel_map); if (rc) { player_op_error(rc, "opening audio device"); __consumer_status_update(CS_STOPPED); __producer_stop(); return rc; } } else if (consumer_status == CS_PAUSED) { op_drop(); op_unpause(); } __consumer_status_update(CS_PLAYING); return 0; }
static int sndio_set_sf(sample_format_t sf) { struct sio_par apar; sndio_sf = sf; sio_initpar(&par); par.pchan = sf_get_channels(sndio_sf); par.rate = sf_get_rate(sndio_sf); sndio_paused = 0; if (sf_get_signed(sndio_sf)) par.sig = 1; else par.sig = 0; if (sf_get_bigendian(sndio_sf)) par.le = 0; else par.le = 1; switch (sf_get_bits(sndio_sf)) { case 16: par.bits = 16; break; case 8: par.bits = 8; break; default: return -OP_ERROR_SAMPLE_FORMAT; } par.appbufsz = par.rate * 300 / 1000; apar = par; if (!sio_setpar(hdl, &par)) return -OP_ERROR_INTERNAL; if (!sio_getpar(hdl, &par)) return -OP_ERROR_INTERNAL; if (apar.rate != par.rate || apar.pchan != par.pchan || apar.bits != par.bits || (par.bits > 8 && apar.le != par.le) || apar.sig != par.sig) return -OP_ERROR_INTERNAL; sndio_mixer_set_volume(sndio_volume, sndio_volume); if (!sio_start(hdl)) return -OP_ERROR_INTERNAL; return OP_ERROR_SUCCESS; }
static void set_buffer_sf(void) { buffer_sf = ip_get_sf(ip); ip_get_channel_map(ip, buffer_channel_map); /* ip_read converts samples to this format */ if (sf_get_channels(buffer_sf) <= 2 && sf_get_bits(buffer_sf) <= 16) { buffer_sf &= SF_RATE_MASK; buffer_sf |= sf_channels(2) | sf_bits(16) | sf_signed(1); buffer_sf |= sf_host_endian(); channel_map_init_stereo(buffer_channel_map); } }
static void scale_samples(char *buffer, unsigned int *countp) { unsigned int count = *countp; int ch, bits, l, r; BUG_ON(scale_pos < consumer_pos); if (consumer_pos != scale_pos) { unsigned int offs = scale_pos - consumer_pos; if (offs >= count) return; buffer += offs; count -= offs; } scale_pos += count; if (replaygain_scale == 1.0 && soft_vol_l == 100 && soft_vol_r == 100) return; ch = sf_get_channels(buffer_sf); bits = sf_get_bits(buffer_sf); if (ch != 2 || (bits != 16 && bits != 24 && bits != 32)) return; l = SOFT_VOL_SCALE; r = SOFT_VOL_SCALE; if (soft_vol && soft_vol_l != 100) l = soft_vol_db[soft_vol_l]; if (soft_vol && soft_vol_r != 100) r = soft_vol_db[soft_vol_r]; l *= replaygain_scale; r *= replaygain_scale; switch (bits) { case 16: SCALE_SAMPLES(int16_t, buffer, count, l, r, sf_need_swap(buffer_sf)); break; case 24: if (likely(!sf_get_bigendian(buffer_sf))) scale_samples_s24le(buffer, count, l, r); break; case 32: SCALE_SAMPLES(int32_t, buffer, count, l, r, sf_need_swap(buffer_sf)); break; } }
static int op_arts_open(sample_format_t sf, const channel_position_t *channel_map) { int buffer_time, server_latency, total_latency; int blocking; arts_sf = sf; arts_stream = arts_play_stream(sf_get_rate(arts_sf), sf_get_bits(arts_sf), sf_get_channels(arts_sf), "cmus"); blocking = arts_stream_set(arts_stream, ARTS_P_BLOCKING, 0); if (blocking) { } arts_buffer_size = arts_stream_get(arts_stream, ARTS_P_BUFFER_SIZE); if (arts_buffer_size < 0) { } buffer_time = arts_stream_get(arts_stream, ARTS_P_BUFFER_TIME); server_latency = arts_stream_get(arts_stream, ARTS_P_SERVER_LATENCY); total_latency = arts_stream_get(arts_stream, ARTS_P_TOTAL_LATENCY); d_print("buffer_time: %d\n", buffer_time); d_print("server_latency: %d\n", server_latency); d_print("total_latency: %d\n", total_latency); return 0; }
static int op_roar_open(sample_format_t sf, const channel_position_t *channel_map) { struct roar_audio_info info; int ret; memset(&info, 0, sizeof(info)); ROAR_DBG("op_roar_open(*) = ?"); format = sf; info.rate = sf_get_rate(sf); info.channels = sf_get_channels(sf); info.bits = sf_get_bits(sf); if (sf_get_bigendian(sf)) { if (sf_get_signed(sf)) { info.codec = ROAR_CODEC_PCM_S_BE; } else { info.codec = ROAR_CODEC_PCM_U_BE; } } else { if (sf_get_signed(sf)) { info.codec = ROAR_CODEC_PCM_S_LE; } else { info.codec = ROAR_CODEC_PCM_U_LE; } } ROAR_DBG("op_roar_open(*) = ?"); if (roar_libroar_set_server(host) == -1) { ROAR_DBG("op_roar_open(*) = ?"); roar_err_to_errno(); return -OP_ERROR_ERRNO; } if ( roar_simple_connect2(&con, NULL, "C* Music Player (cmus)", ROAR_ENUM_FLAG_NONBLOCK, 0) == -1 ) { ROAR_DBG("op_roar_open(*) = ?"); roar_err_to_errno(); return -OP_ERROR_ERRNO; } vss = roar_vs_new_from_con(&con, &err); if (vss == NULL) { ROAR_DBG("op_roar_open(*) = ?"); roar_disconnect(&con); _err_to_errno(); return -OP_ERROR_ERRNO; } if (roar_vs_stream(vss, &info, ROAR_DIR_PLAY, &err) == -1) { ROAR_DBG("op_roar_open(*) = ?"); roar_disconnect(&con); _err_to_errno(); return -OP_ERROR_ERRNO; } ROAR_DBG("op_roar_open(*) = ?"); if (roar_vs_buffer(vss, 2048*8, &err) == -1) { roar_vs_close(vss, ROAR_VS_TRUE, NULL); roar_disconnect(&con); _err_to_errno(); return -OP_ERROR_ERRNO; } ROAR_DBG("op_roar_open(*) = ?"); ret = _set_role(); if (ret != 0) { roar_vs_close(vss, ROAR_VS_TRUE, NULL); roar_disconnect(&con); _err_to_errno(); return ret; } ROAR_DBG("op_roar_open(*) = ?"); if (roar_vs_blocking(vss, ROAR_VS_FALSE, &err) == -1) { /* FIXME: handle this error */ } ROAR_DBG("op_roar_open(*) = 0"); return 0; }
0, NULL, layout_size, layout); if (err != noErr) d_print("Cannot set the channel layout successfully.\n"); free(layout); } static AudioStreamBasicDescription coreaudio_fill_format_description(sample_format_t sf) { AudioStreamBasicDescription desc = { .mSampleRate = (Float64)sf_get_rate(sf), .mFormatID = kAudioFormatLinearPCM, .mFormatFlags = kAudioFormatFlagIsPacked, .mBytesPerPacket = sf_get_frame_size(sf), .mFramesPerPacket = 1, .mChannelsPerFrame = sf_get_channels(sf), .mBitsPerChannel = sf_get_bits(sf), .mBytesPerFrame = sf_get_frame_size(sf), }; d_print("Bits:%d\n", sf_get_bits(sf)); if (sf_get_bigendian(sf)) desc.mFormatFlags |= kAudioFormatFlagIsBigEndian; if (sf_get_signed(sf)) desc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger; return desc; } static void coreaudio_sync_device_sample_rate(AudioDeviceID dev_id, AudioStreamBasicDescription desc) {
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 }
static int oss_set_sf(sample_format_t sf) { int tmp, log2_fragment_size, nr_fragments, bytes_per_second; oss_reset(); oss_sf = sf; #ifdef SNDCTL_DSP_CHANNELS tmp = sf_get_channels(oss_sf); if (ioctl(oss_fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) return -1; #else tmp = sf_get_channels(oss_sf) - 1; if (ioctl(oss_fd, SNDCTL_DSP_STEREO, &tmp) == -1) return -1; #endif if (sf_get_bits(oss_sf) == 16) { if (sf_get_signed(oss_sf)) { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_S16_BE; } else { tmp = AFMT_S16_LE; } } else { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_U16_BE; } else { tmp = AFMT_U16_LE; } } } else if (sf_get_bits(oss_sf) == 8) { if (sf_get_signed(oss_sf)) { tmp = AFMT_S8; } else { tmp = AFMT_U8; } } else if (sf_get_bits(oss_sf) == 32 && sf_get_signed(oss_sf)) { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_S32_BE; } else { tmp = AFMT_S32_LE; } } else if (sf_get_bits(oss_sf) == 24 && sf_get_signed(oss_sf) && !sf_get_bigendian(oss_sf)) { tmp = AFMT_S24_PACKED; } else { d_print("unsupported sample format: %c%u_%s\n", sf_get_signed(oss_sf) ? 'S' : 'U', sf_get_bits(oss_sf), sf_get_bigendian(oss_sf) ? "BE" : "LE"); return -1; } if (ioctl(oss_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1) return -1; tmp = sf_get_rate(oss_sf); if (ioctl(oss_fd, SNDCTL_DSP_SPEED, &tmp) == -1) return -1; bytes_per_second = sf_get_second_size(oss_sf); log2_fragment_size = 0; while (1 << log2_fragment_size < bytes_per_second / 25) log2_fragment_size++; log2_fragment_size--; nr_fragments = 32; /* bits 0..15 = size of fragment, 16..31 = log2(number of fragments) */ tmp = (nr_fragments << 16) + log2_fragment_size; if (ioctl(oss_fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) return -1; return 0; }