1 #include "alsa_input.h"
3 #include <alsa/error.h>
10 #include "bmusb/bmusb.h"
14 using namespace std::placeholders;
16 #define RETURN_ON_ERROR(msg, expr) do { \
19 fprintf(stderr, "[%s] " msg ": %s\n", device.c_str(), snd_strerror(err)); \
20 if (err == -ENODEV) return CaptureEndReason::DEVICE_GONE; \
21 return CaptureEndReason::OTHER_ERROR; \
25 #define RETURN_FALSE_ON_ERROR(msg, expr) do { \
28 fprintf(stderr, "[%s] " msg ": %s\n", device.c_str(), snd_strerror(err)); \
33 #define WARN_ON_ERROR(msg, expr) do { \
36 fprintf(stderr, "[%s] " msg ": %s\n", device.c_str(), snd_strerror(err)); \
40 ALSAInput::ALSAInput(const char *device, unsigned sample_rate, unsigned num_channels, audio_callback_t audio_callback, ALSAPool *parent_pool, unsigned internal_dev_index)
42 sample_rate(sample_rate),
43 num_channels(num_channels),
44 audio_callback(audio_callback),
45 parent_pool(parent_pool),
46 internal_dev_index(internal_dev_index)
50 bool ALSAInput::open_device()
52 RETURN_FALSE_ON_ERROR("snd_pcm_open()", snd_pcm_open(&pcm_handle, device.c_str(), SND_PCM_STREAM_CAPTURE, 0));
55 snd_pcm_hw_params_t *hw_params;
56 snd_pcm_hw_params_alloca(&hw_params);
57 if (!set_base_params(device.c_str(), pcm_handle, hw_params, &sample_rate)) {
61 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params_set_channels()", snd_pcm_hw_params_set_channels(pcm_handle, hw_params, num_channels));
63 // Fragment size of 64 samples (about 1 ms at 48 kHz; a frame at 60
64 // fps/48 kHz is 800 samples.) We ask for 64 such periods in our buffer
65 // (~85 ms buffer); more than that, and our jitter is probably so high
66 // that the resampling queue can't keep up anyway.
67 // The entire thing with periods and such is a bit mysterious to me;
68 // seemingly I can get 96 frames at a time with no problems even if
69 // the period size is 64 frames. And if I set num_periods to e.g. 1,
70 // I can't have a big buffer.
73 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params_set_periods_near()", snd_pcm_hw_params_set_periods_near(pcm_handle, hw_params, &num_periods, &dir));
76 RETURN_FALSE_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));
77 buffer_frames = 64 * 64;
78 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params_set_buffer_size_near()", snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hw_params, &buffer_frames));
79 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params()", snd_pcm_hw_params(pcm_handle, hw_params));
80 //snd_pcm_hw_params_free(hw_params);
82 // Figure out which format the card actually chose.
83 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params_current()", snd_pcm_hw_params_current(pcm_handle, hw_params));
84 snd_pcm_format_t chosen_format;
85 RETURN_FALSE_ON_ERROR("snd_pcm_hw_params_get_format()", snd_pcm_hw_params_get_format(hw_params, &chosen_format));
87 audio_format.num_channels = num_channels;
88 audio_format.bits_per_sample = 0;
89 switch (chosen_format) {
90 case SND_PCM_FORMAT_S16_LE:
91 audio_format.bits_per_sample = 16;
93 case SND_PCM_FORMAT_S24_LE:
94 audio_format.bits_per_sample = 24;
96 case SND_PCM_FORMAT_S32_LE:
97 audio_format.bits_per_sample = 32;
102 //printf("num_periods=%u period_size=%u buffer_frames=%u sample_rate=%u bits_per_sample=%d\n",
103 // num_periods, unsigned(period_size), unsigned(buffer_frames), sample_rate, audio_format.bits_per_sample);
105 buffer.reset(new uint8_t[buffer_frames * num_channels * audio_format.bits_per_sample / 8]);
107 snd_pcm_sw_params_t *sw_params;
108 snd_pcm_sw_params_alloca(&sw_params);
109 RETURN_FALSE_ON_ERROR("snd_pcm_sw_params_current()", snd_pcm_sw_params_current(pcm_handle, sw_params));
110 RETURN_FALSE_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));
111 RETURN_FALSE_ON_ERROR("snd_pcm_sw_params()", snd_pcm_sw_params(pcm_handle, sw_params));
113 RETURN_FALSE_ON_ERROR("snd_pcm_nonblock()", snd_pcm_nonblock(pcm_handle, 1));
114 RETURN_FALSE_ON_ERROR("snd_pcm_prepare()", snd_pcm_prepare(pcm_handle));
118 bool ALSAInput::set_base_params(const char *device_name, snd_pcm_t *pcm_handle, snd_pcm_hw_params_t *hw_params, unsigned *sample_rate)
121 err = snd_pcm_hw_params_any(pcm_handle, hw_params);
123 fprintf(stderr, "[%s] snd_pcm_hw_params_any(): %s\n", device_name, snd_strerror(err));
126 err = snd_pcm_hw_params_set_access(pcm_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);
128 fprintf(stderr, "[%s] snd_pcm_hw_params_set_access(): %s\n", device_name, snd_strerror(err));
131 snd_pcm_format_mask_t *format_mask;
132 snd_pcm_format_mask_alloca(&format_mask);
133 snd_pcm_format_mask_set(format_mask, SND_PCM_FORMAT_S16_LE);
134 snd_pcm_format_mask_set(format_mask, SND_PCM_FORMAT_S24_LE);
135 snd_pcm_format_mask_set(format_mask, SND_PCM_FORMAT_S32_LE);
136 err = snd_pcm_hw_params_set_format_mask(pcm_handle, hw_params, format_mask);
138 fprintf(stderr, "[%s] snd_pcm_hw_params_set_format_mask(): %s\n", device_name, snd_strerror(err));
141 err = snd_pcm_hw_params_set_rate_near(pcm_handle, hw_params, sample_rate, 0);
143 fprintf(stderr, "[%s] snd_pcm_hw_params_set_rate_near(): %s\n", device_name, snd_strerror(err));
149 ALSAInput::~ALSAInput()
152 WARN_ON_ERROR("snd_pcm_close()", snd_pcm_close(pcm_handle));
156 void ALSAInput::start_capture_thread()
159 capture_thread = thread(&ALSAInput::capture_thread_func, this);
162 void ALSAInput::stop_capture_thread()
165 capture_thread.join();
168 void ALSAInput::capture_thread_func()
170 parent_pool->set_card_state(internal_dev_index, ALSAPool::Device::State::STARTING);
172 // If the device hasn't been opened already, we need to do so
173 // before we can capture.
174 while (!should_quit && pcm_handle == nullptr) {
175 if (!open_device()) {
176 fprintf(stderr, "[%s] Waiting one second and trying again...\n",
183 // Don't call free_card(); that would be a deadlock.
184 WARN_ON_ERROR("snd_pcm_close()", snd_pcm_close(pcm_handle));
185 pcm_handle = nullptr;
189 // Do the actual capture. (Termination condition within loop.)
191 switch (do_capture()) {
192 case CaptureEndReason::REQUESTED_QUIT:
193 // Don't call free_card(); that would be a deadlock.
194 WARN_ON_ERROR("snd_pcm_close()", snd_pcm_close(pcm_handle));
195 pcm_handle = nullptr;
197 case CaptureEndReason::DEVICE_GONE:
198 parent_pool->free_card(internal_dev_index);
199 WARN_ON_ERROR("snd_pcm_close()", snd_pcm_close(pcm_handle));
200 pcm_handle = nullptr;
202 case CaptureEndReason::OTHER_ERROR:
203 parent_pool->set_card_state(internal_dev_index, ALSAPool::Device::State::STARTING);
204 fprintf(stderr, "[%s] Sleeping one second and restarting capture...\n",
212 ALSAInput::CaptureEndReason ALSAInput::do_capture()
214 parent_pool->set_card_state(internal_dev_index, ALSAPool::Device::State::STARTING);
215 RETURN_ON_ERROR("snd_pcm_start()", snd_pcm_start(pcm_handle));
216 parent_pool->set_card_state(internal_dev_index, ALSAPool::Device::State::RUNNING);
218 uint64_t num_frames_output = 0;
219 while (!should_quit) {
220 int ret = snd_pcm_wait(pcm_handle, /*timeout=*/100);
221 if (ret == 0) continue; // Timeout.
223 fprintf(stderr, "[%s] ALSA overrun\n", device.c_str());
224 snd_pcm_prepare(pcm_handle);
225 snd_pcm_start(pcm_handle);
228 RETURN_ON_ERROR("snd_pcm_wait()", ret);
230 snd_pcm_sframes_t frames = snd_pcm_readi(pcm_handle, buffer.get(), buffer_frames);
231 if (frames == -EPIPE) {
232 fprintf(stderr, "[%s] ALSA overrun\n", device.c_str());
233 snd_pcm_prepare(pcm_handle);
234 snd_pcm_start(pcm_handle);
238 fprintf(stderr, "snd_pcm_readi() returned 0\n");
241 RETURN_ON_ERROR("snd_pcm_readi()", frames);
243 const int64_t prev_pts = frames_to_pts(num_frames_output);
244 const int64_t pts = frames_to_pts(num_frames_output + frames);
247 if (should_quit) return CaptureEndReason::REQUESTED_QUIT;
248 success = audio_callback(buffer.get(), frames, audio_format, pts - prev_pts);
250 num_frames_output += frames;
252 return CaptureEndReason::REQUESTED_QUIT;
255 int64_t ALSAInput::frames_to_pts(uint64_t n) const
257 return (n * TIMEBASE) / sample_rate;