Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alsa: limit buffer size, so shairport can start in time #345

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 47 additions & 5 deletions audio_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ static void start(int sample_rate) {
die("Unexpected sample rate!");

int ret, dir = 0;
snd_pcm_uframes_t frames = 64;
snd_pcm_uframes_t period_size, buffer_size;
ret = snd_pcm_open(&alsa_handle, alsa_out_dev, SND_PCM_STREAM_PLAYBACK, 0);
if (ret < 0)
die("Alsa initialization failed: unable to open pcm device: %s\n", snd_strerror(ret));
Expand All @@ -166,10 +166,52 @@ static void start(int sample_rate) {
snd_pcm_hw_params_set_format(alsa_handle, alsa_params, SND_PCM_FORMAT_S16);
snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, (unsigned int *)&sample_rate, &dir);
snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params, &frames, &dir);
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0)
die("unable to set hw parameters: %s\n", snd_strerror(ret));

// setting period and buffer is a simplified version of what XBMC does
snd_pcm_hw_params_get_period_size_max(alsa_params, &period_size, NULL);
snd_pcm_hw_params_get_buffer_size_max(alsa_params, &buffer_size);
debug(1, "Hardware supports period_size_max: %d, buffer_size_max: %d\n", period_size, buffer_size);

// we want about 333 ms of buffer, and 50ms period
// buffer might still need some tweaking to get reliable operation on RPi + USB DAC...
// make sure we do not exceed what HW supports
period_size = (period_size < sample_rate / 20 ? period_size : sample_rate / 20);
buffer_size = (buffer_size < sample_rate / 3 ? buffer_size : sample_rate / 3);

// make sure buffer size is at least 4 times period size
period_size = (period_size < buffer_size / 4 ? period_size : buffer_size / 4);
debug(1, "Trying to set period_size: %d, buffer_size: %d\n", period_size, buffer_size);

// we keep the originals and try setting period and buffer using copies
snd_pcm_uframes_t period_temp, buffer_temp;
period_temp = period_size;
buffer_temp = buffer_size;
snd_pcm_hw_params_t *alsa_params_copy;
snd_pcm_hw_params_alloca(&alsa_params_copy);
snd_pcm_hw_params_copy(alsa_params_copy, alsa_params);

// some HW seems to be picky about the order period and buffer are set, so try both ways
// first try with buffer_size, period_size
if (snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params_copy, &buffer_temp) != 0
|| snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params_copy, &period_temp, NULL) != 0
|| snd_pcm_hw_params(alsa_handle, alsa_params_copy) != 0) {
period_temp = period_size;
buffer_temp = buffer_size;
snd_pcm_hw_params_copy(alsa_params_copy, alsa_params);
// retry with period_size, buffer_size
if (snd_pcm_hw_params_set_period_size_near(alsa_handle, alsa_params_copy, &period_temp, NULL) != 0
|| snd_pcm_hw_params_set_buffer_size_near(alsa_handle, alsa_params_copy, &buffer_temp) != 0
|| snd_pcm_hw_params(alsa_handle, alsa_params_copy) != 0) {
// set what alsa would have
warn("Setting period and buffer failed, going with the defaults\n");
ret = snd_pcm_hw_params(alsa_handle, alsa_params);
if (ret < 0)
die("unable to set hw parameters: %s\n", snd_strerror(ret));
// using alsa defaults, so see what they are
snd_pcm_get_params(alsa_handle, &buffer_size, &period_size);
debug(1, "Defaults are period_size: %d, buffer_size: %d\n", period_size, buffer_size);
}
}
}

static void play(short buf[], int samples) {
Expand Down