1 #include "alsa_output.h"
9 void die_on_error(const char *func_name, int err)
12 fprintf(stderr, "%s: %s\n", func_name, snd_strerror(err));
19 ALSAOutput::ALSAOutput(int sample_rate, int num_channels)
20 : num_channels(num_channels)
22 die_on_error("snd_pcm_open()", snd_pcm_open(&pcm_handle, "default", SND_PCM_STREAM_PLAYBACK, 0));
25 snd_pcm_hw_params_t *hw_params;
26 snd_pcm_hw_params_alloca(&hw_params);
27 die_on_error("snd_pcm_hw_params_any()", snd_pcm_hw_params_any(pcm_handle, hw_params));
28 die_on_error("snd_pcm_hw_params_set_access()", snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED));
29 die_on_error("snd_pcm_hw_params_set_format()", snd_pcm_hw_params_set_format(pcm_handle, hw_params, SND_PCM_FORMAT_FLOAT_LE));
30 die_on_error("snd_pcm_hw_params_set_rate()", snd_pcm_hw_params_set_rate(pcm_handle, hw_params, sample_rate, 0));
31 die_on_error("snd_pcm_hw_params_set_channels", snd_pcm_hw_params_set_channels(pcm_handle, hw_params, num_channels));
33 // Fragment size of 512 samples. (A frame at 60 fps/48 kHz is 800 samples.)
34 // We ask for 16 such periods (~170 ms buffer).
35 unsigned int num_periods = 16;
37 die_on_error("snd_pcm_hw_params_set_periods_near()", snd_pcm_hw_params_set_periods_near(pcm_handle, hw_params, &num_periods, &dir));
40 die_on_error("snd_pcm_hw_params_set_period_size_near()", snd_pcm_hw_params_set_period_size_near(pcm_handle, hw_params, &period_size, &dir));
41 die_on_error("snd_pcm_hw_params()", snd_pcm_hw_params(pcm_handle, hw_params));
42 //snd_pcm_hw_params_free(hw_params);
44 snd_pcm_sw_params_t *sw_params;
45 snd_pcm_sw_params_alloca(&sw_params);
46 die_on_error("snd_pcm_sw_params_current()", snd_pcm_sw_params_current(pcm_handle, sw_params));
47 die_on_error("snd_pcm_sw_params_set_start_threshold", snd_pcm_sw_params_set_start_threshold(pcm_handle, sw_params, num_periods * period_size / 2));
48 die_on_error("snd_pcm_sw_params()", snd_pcm_sw_params(pcm_handle, sw_params));
50 die_on_error("snd_pcm_nonblock", snd_pcm_nonblock(pcm_handle, 1));
51 die_on_error("snd_pcm_prepare()", snd_pcm_prepare(pcm_handle));
54 void ALSAOutput::write(const vector<float> &samples)
56 buffer.insert(buffer.end(), samples.begin(), samples.end());
59 int periods_to_write = buffer.size() / (period_size * num_channels);
60 if (periods_to_write == 0) {
64 int ret = snd_pcm_writei(pcm_handle, buffer.data(), periods_to_write * period_size);
66 fprintf(stderr, "warning: snd_pcm_writei() reported underrun\n");
67 snd_pcm_recover(pcm_handle, ret, 1);
69 } else if (ret == -EAGAIN) {
72 fprintf(stderr, "error: snd_pcm_writei() returned '%s'\n", snd_strerror(ret));
75 buffer.erase(buffer.begin(), buffer.begin() + ret * num_channels);
78 if (buffer.size() >= period_size * num_channels) { // Still more to write.
80 if (buffer.size() >= period_size * num_channels * 8) {
81 // OK, almost 100 ms. Giving up.
82 fprintf(stderr, "warning: ALSA overrun, dropping some audio\n");
86 // Not a completely failure (effectively a short write),
87 // possibly due to a signal.