static int laudio_alsa_open(void) { snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t bufsize; int ret; hw_params = NULL; ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret)); return -1; } /* HW params */ ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_any(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); goto out_fail; } snd_pcm_hw_params_free(hw_params); hw_params = NULL; pcm_pos = 0; pcm_last_error = 0; pcm_recovery = 0; pcm_buf_threshold = (bufsize / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; ret = mixer_open(); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n"); goto out_fail; } update_status(LAUDIO_OPEN); return 0; out_fail: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(hdl); hdl = NULL; return -1; }
static int laudio_alsa_open(void) { snd_pcm_hw_params_t *hw_params; snd_pcm_uframes_t bufsize; snd_pcm_uframes_t period_size; int ret; hw_params = NULL; ret = snd_pcm_open(&hdl, card_name, SND_PCM_STREAM_PLAYBACK, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open playback device: %s\n", snd_strerror(ret)); return -1; } /* HW params */ ret = snd_pcm_hw_params_malloc(&hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not allocate hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_any(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not retrieve hw params: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_access(hdl, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set access method: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_format(hdl, hw_params, SND_PCM_FORMAT_S16_LE); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set S16LE format: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_channels(hdl, hw_params, 2); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set stereo output: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_set_rate(hdl, hw_params, 44100, 0); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Hardware doesn't support 44.1 kHz: %s\n", snd_strerror(ret)); goto out_fail; } ret = snd_pcm_hw_params_get_buffer_size_max(hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not get max buffer size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Max buffer size is %lu samples\n", bufsize); ret = snd_pcm_hw_params_set_buffer_size_max(hdl, hw_params, &bufsize); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set buffer size to max: %s\n", snd_strerror(ret)); goto out_fail; } // With a small period size we seem to get underruns because the period time // passes before we manage to feed with samples (if the player is slightly // behind - especially critical during startup when the buffer is low) // Internet suggests period_size should be /2 bufsize, but default seems to be // much lower, so compromise on /4 (but not more than 65536 frames = almost 2 sec). period_size = bufsize / 4; if (period_size > 65536) period_size = 65536; ret = snd_pcm_hw_params_set_period_size_near(hdl, hw_params, &period_size, NULL); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set period size: %s\n", snd_strerror(ret)); goto out_fail; } DPRINTF(E_DBG, L_LAUDIO, "Buffer size is %lu samples, period size is %lu samples\n", bufsize, period_size); ret = snd_pcm_hw_params(hdl, hw_params); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not set hw params: %s\n", snd_strerror(ret)); goto out_fail; } snd_pcm_hw_params_free(hw_params); hw_params = NULL; pcm_pos = 0; pcm_last_error = 0; pcm_recovery = 0; pcm_buf_threshold = ((bufsize - period_size) / AIRTUNES_V2_PACKET_SAMPLES) * AIRTUNES_V2_PACKET_SAMPLES; pcm_period_size = period_size; ret = mixer_open(); if (ret < 0) { DPRINTF(E_LOG, L_LAUDIO, "Could not open mixer\n"); goto out_fail; } update_status(LAUDIO_OPEN); return 0; out_fail: if (hw_params) snd_pcm_hw_params_free(hw_params); snd_pcm_close(hdl); hdl = NULL; return -1; }
bool AlsaSound::AlsaInit() { unsigned int sample_rate = m_mixer->GetSampleRate(); int err; int dir; snd_pcm_sw_params_t *swparams; snd_pcm_hw_params_t *hwparams; snd_pcm_uframes_t buffer_size,buffer_size_max; unsigned int periods; err = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); if (err < 0) { ERROR_LOG(AUDIO, "Audio open error: %s\n", snd_strerror(err)); return false; } snd_pcm_hw_params_alloca(&hwparams); err = snd_pcm_hw_params_any(handle, hwparams); if (err < 0) { ERROR_LOG(AUDIO, "Broken configuration for this PCM: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_access(handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED); if (err < 0) { ERROR_LOG(AUDIO, "Access type not available: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_format(handle, hwparams, SND_PCM_FORMAT_S16_LE); if (err < 0) { ERROR_LOG(AUDIO, "Sample format not available: %s\n", snd_strerror(err)); return false; } dir = 0; err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &sample_rate, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Rate not available: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_set_channels(handle, hwparams, 2); if (err < 0) { ERROR_LOG(AUDIO, "Channels count not available: %s\n", snd_strerror(err)); return false; } periods = BUFFER_SIZE_MAX / FRAME_COUNT_MIN; err = snd_pcm_hw_params_set_periods_max(handle, hwparams, &periods, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Cannot set Minimum periods: %s\n", snd_strerror(err)); return false; } buffer_size_max = BUFFER_SIZE_MAX; err = snd_pcm_hw_params_set_buffer_size_max(handle, hwparams, &buffer_size_max); if (err < 0) { ERROR_LOG(AUDIO, "Cannot set minimum buffer size: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params(handle, hwparams); if (err < 0) { ERROR_LOG(AUDIO, "Unable to install hw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); if (err < 0) { ERROR_LOG(AUDIO, "Cannot get buffer size: %s\n", snd_strerror(err)); return false; } err = snd_pcm_hw_params_get_periods_max(hwparams, &periods, &dir); if (err < 0) { ERROR_LOG(AUDIO, "Cannot get periods: %s\n", snd_strerror(err)); return false; } //periods is the number of fragments alsa can wait for during one //buffer_size frames_to_deliver = buffer_size / periods; //limit the minimum size. pulseaudio advertises a minimum of 32 samples. if (frames_to_deliver < FRAME_COUNT_MIN) frames_to_deliver = FRAME_COUNT_MIN; //it is probably a bad idea to try to send more than one buffer of data if ((unsigned int)frames_to_deliver > buffer_size) frames_to_deliver = buffer_size; NOTICE_LOG(AUDIO, "ALSA gave us a %ld sample \"hardware\" buffer with %d periods. Will send %d samples per fragments.\n", buffer_size, periods, frames_to_deliver); snd_pcm_sw_params_alloca(&swparams); err = snd_pcm_sw_params_current(handle, swparams); if (err < 0) { ERROR_LOG(AUDIO, "cannot init sw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_sw_params_set_start_threshold(handle, swparams, 0U); if (err < 0) { ERROR_LOG(AUDIO, "cannot set start thresh: %s\n", snd_strerror(err)); return false; } err = snd_pcm_sw_params(handle, swparams); if (err < 0) { ERROR_LOG(AUDIO, "cannot set sw params: %s\n", snd_strerror(err)); return false; } err = snd_pcm_prepare(handle); if (err < 0) { ERROR_LOG(AUDIO, "Unable to prepare: %s\n", snd_strerror(err)); return false; } NOTICE_LOG(AUDIO, "ALSA successfully initialized.\n"); return true; }
struct codec * alsa_codec_init(const char *path, const char *type, const char *enc, int fs, int channels, int endian, int mode) { int err; snd_pcm_t *dev = NULL; snd_pcm_hw_params_t *p = NULL; struct codec *c = NULL; struct alsa_state *state = NULL; snd_pcm_uframes_t buf_frames; struct alsa_enc_info *enc_info; if ((err = snd_pcm_open(&dev, path, (mode == CODEC_MODE_WRITE) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, 0)) < 0) { LOG(LL_OPEN_ERROR, "dsp: alsa: error: failed to open device: %s\n", snd_strerror(err)); goto fail; } if ((enc_info = alsa_get_enc_info(enc)) == NULL) { LOG(LL_ERROR, "dsp: alsa: error: bad encoding: %s\n", enc); goto fail; } if ((err = snd_pcm_hw_params_malloc(&p)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to allocate hw params: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_any(dev, p)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to initialize hw params: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_access(dev, p, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set access: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_format(dev, p, enc_info->fmt)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set format: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_rate(dev, p, (unsigned int) fs, 0)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set rate: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params_set_channels(dev, p, channels)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set channels: %s\n", snd_strerror(err)); goto fail; } buf_frames = dsp_globals.buf_frames; if ((err = snd_pcm_hw_params_set_buffer_size_min(dev, p, &buf_frames)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set buffer size minimum: %s\n", snd_strerror(err)); goto fail; } buf_frames = dsp_globals.buf_frames * dsp_globals.max_buf_ratio; if ((err = snd_pcm_hw_params_set_buffer_size_max(dev, p, &buf_frames)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set buffer size maximum: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_hw_params(dev, p)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to set params: %s\n", snd_strerror(err)); goto fail; } if ((err = snd_pcm_prepare(dev)) < 0) { LOG(LL_ERROR, "dsp: alsa: error: failed to prepare device: %s\n", snd_strerror(err)); goto fail; } state = calloc(1, sizeof(struct alsa_state)); state->dev = dev; state->enc_info = enc_info; state->delay = 0; if (mode == CODEC_MODE_WRITE) { state->buf = calloc(dsp_globals.buf_frames * channels, enc_info->bytes); state->buf_frames = dsp_globals.buf_frames; } c = calloc(1, sizeof(struct codec)); c->path = path; c->type = type; c->enc = enc_info->name; c->fs = fs; c->channels = channels; c->prec = enc_info->prec; c->interactive = (mode == CODEC_MODE_WRITE) ? 1 : 0; c->frames = -1; c->read = alsa_read; c->write = alsa_write; c->seek = alsa_seek; c->delay = alsa_delay; c->drop = alsa_drop; c->pause = alsa_pause; c->destroy = alsa_destroy; c->data = state; snd_pcm_hw_params_free(p); return c; fail: if (p != NULL) snd_pcm_hw_params_free(p); if (dev != NULL) snd_pcm_close(dev); return NULL; }