3 #include <alsa/asoundlib.h>
4 #include <alsa/control.h>
5 #include <alsa/error.h>
10 #include <linux/limits.h>
17 #include <sys/eventfd.h>
18 #include <sys/inotify.h>
29 #include "alsa_input.h"
30 #include "audio_mixer.h"
31 #include "card_type.h"
32 #include "input_mapping.h"
33 #include "shared/shared_defs.h"
37 using namespace std::placeholders;
41 should_quit_fd = eventfd(/*initval=*/0, /*flags=*/0);
42 assert(should_quit_fd != -1);
47 for (Device &device : devices) {
48 if (device.input != nullptr) {
49 device.input->stop_capture_thread();
53 const uint64_t one = 1;
54 if (write(should_quit_fd, &one, sizeof(one)) != sizeof(one)) {
55 perror("write(should_quit_fd)");
58 inotify_thread.join();
60 while (retry_threads_running > 0) {
61 this_thread::sleep_for(std::chrono::milliseconds(100));
65 std::vector<ALSAPool::Device> ALSAPool::get_devices()
67 lock_guard<mutex> lock(mu);
68 for (Device &device : devices) {
74 void ALSAPool::hold_device(unsigned index)
76 lock_guard<mutex> lock(mu);
77 assert(index < devices.size());
78 devices[index].held = true;
81 void ALSAPool::release_device(unsigned index)
83 lock_guard<mutex> lock(mu);
84 if (index < devices.size()) {
85 devices[index].held = false;
89 void ALSAPool::enumerate_devices()
91 // Enumerate all cards.
92 for (int card_index = -1; snd_card_next(&card_index) == 0 && card_index >= 0; ) {
94 snprintf(address, sizeof(address), "hw:%d", card_index);
97 int err = snd_ctl_open(&ctl, address, 0);
99 printf("%s: %s\n", address, snd_strerror(err));
102 unique_ptr<snd_ctl_t, decltype(snd_ctl_close)*> ctl_closer(ctl, snd_ctl_close);
104 // Enumerate all devices on this card.
105 for (int dev_index = -1; snd_ctl_pcm_next_device(ctl, &dev_index) == 0 && dev_index >= 0; ) {
106 probe_device_with_retry(card_index, dev_index);
111 void ALSAPool::probe_device_with_retry(unsigned card_index, unsigned dev_index)
114 snprintf(address, sizeof(address), "hw:%d,%d", card_index, dev_index);
116 lock_guard<mutex> lock(add_device_mutex);
117 if (add_device_tries_left.count(address)) {
118 // Some thread is already busy retrying this,
119 // so just reset its count.
120 add_device_tries_left[address] = num_retries;
124 // Try (while still holding the lock) to add the device synchronously.
125 ProbeResult result = probe_device_once(card_index, dev_index);
126 if (result == ProbeResult::SUCCESS) {
128 } else if (result == ProbeResult::FAILURE) {
131 assert(result == ProbeResult::DEFER);
133 // Add failed for whatever reason (probably just that the device
134 // isn't up yet. Set up a count so that nobody else starts a thread,
135 // then start it ourselves.
136 fprintf(stderr, "Trying %s again in one second...\n", address);
137 add_device_tries_left[address] = num_retries;
138 ++retry_threads_running;
139 thread(&ALSAPool::probe_device_retry_thread_func, this, card_index, dev_index).detach();
142 void ALSAPool::probe_device_retry_thread_func(unsigned card_index, unsigned dev_index)
145 snprintf(address, sizeof(address), "hw:%d,%d", card_index, dev_index);
147 char thread_name[16];
148 snprintf(thread_name, sizeof(thread_name), "Reprobe_hw:%d,%d", card_index, dev_index);
149 pthread_setname_np(pthread_self(), thread_name);
151 for ( ;; ) { // Termination condition within the loop.
154 // See if there are any retries left.
155 lock_guard<mutex> lock(add_device_mutex);
157 !add_device_tries_left.count(address) ||
158 add_device_tries_left[address] == 0) {
159 add_device_tries_left.erase(address);
160 fprintf(stderr, "Giving up probe of %s.\n", address);
164 // Seemingly there were. Give it a try (we still hold the mutex).
165 ProbeResult result = probe_device_once(card_index, dev_index);
166 if (result == ProbeResult::SUCCESS) {
167 add_device_tries_left.erase(address);
168 fprintf(stderr, "Probe of %s succeeded.\n", address);
170 } else if (result == ProbeResult::FAILURE || --add_device_tries_left[address] == 0) {
171 add_device_tries_left.erase(address);
172 fprintf(stderr, "Giving up probe of %s.\n", address);
177 assert(result == ProbeResult::DEFER);
178 fprintf(stderr, "Trying %s again in one second (%d tries left)...\n",
179 address, add_device_tries_left[address]);
182 --retry_threads_running;
185 ALSAPool::ProbeResult ALSAPool::probe_device_once(unsigned card_index, unsigned dev_index)
188 snprintf(address, sizeof(address), "hw:%d", card_index);
190 int err = snd_ctl_open(&ctl, address, 0);
192 printf("%s: %s\n", address, snd_strerror(err));
193 return ALSAPool::ProbeResult::DEFER;
195 unique_ptr<snd_ctl_t, decltype(snd_ctl_close)*> ctl_closer(ctl, snd_ctl_close);
197 snprintf(address, sizeof(address), "hw:%d,%d", card_index, dev_index);
199 snd_pcm_info_t *pcm_info;
200 snd_pcm_info_alloca(&pcm_info);
201 snd_pcm_info_set_device(pcm_info, dev_index);
202 snd_pcm_info_set_subdevice(pcm_info, 0);
203 snd_pcm_info_set_stream(pcm_info, SND_PCM_STREAM_CAPTURE);
204 err = snd_ctl_pcm_info(ctl, pcm_info);
205 if (err == -ENOENT) {
206 // Not a capture card.
207 return ALSAPool::ProbeResult::FAILURE;
210 // Not available for capture.
211 printf("%s: Not available for capture.\n", address);
212 return ALSAPool::ProbeResult::DEFER;
215 unsigned num_channels = 0;
217 // Find all channel maps for this device, and pick out the one
218 // with the most channels.
219 snd_pcm_chmap_query_t **cmaps = snd_pcm_query_chmaps_from_hw(card_index, dev_index, 0, SND_PCM_STREAM_CAPTURE);
220 if (cmaps != nullptr) {
221 for (snd_pcm_chmap_query_t **ptr = cmaps; *ptr; ++ptr) {
222 num_channels = max(num_channels, (*ptr)->map.channels);
224 snd_pcm_free_chmaps(cmaps);
226 if (num_channels == 0) {
227 // Device had no channel maps. We need to open it to query.
228 // TODO: Do this asynchronously.
229 snd_pcm_t *pcm_handle;
230 int err = snd_pcm_open(&pcm_handle, address, SND_PCM_STREAM_CAPTURE, 0);
232 printf("%s: %s\n", address, snd_strerror(err));
233 return ALSAPool::ProbeResult::DEFER;
235 snd_pcm_hw_params_t *hw_params;
236 snd_pcm_hw_params_alloca(&hw_params);
237 unsigned sample_rate;
238 if (!ALSAInput::set_base_params(address, pcm_handle, hw_params, &sample_rate)) {
239 snd_pcm_close(pcm_handle);
240 return ALSAPool::ProbeResult::DEFER;
242 err = snd_pcm_hw_params_get_channels_max(hw_params, &num_channels);
244 fprintf(stderr, "[%s] snd_pcm_hw_params_get_channels_max(): %s\n",
245 address, snd_strerror(err));
246 snd_pcm_close(pcm_handle);
247 return ALSAPool::ProbeResult::DEFER;
249 snd_pcm_close(pcm_handle);
252 if (num_channels == 0) {
253 printf("%s: No channel maps with channels\n", address);
254 return ALSAPool::ProbeResult::FAILURE;
257 snd_ctl_card_info_t *card_info;
258 snd_ctl_card_info_alloca(&card_info);
259 snd_ctl_card_info(ctl, card_info);
261 string name = snd_ctl_card_info_get_name(card_info);
262 string info = snd_pcm_info_get_name(pcm_info);
264 unsigned internal_dev_index;
267 lock_guard<mutex> lock(mu);
268 internal_dev_index = find_free_device_index(name, info, num_channels, address);
269 devices[internal_dev_index].address = address;
270 devices[internal_dev_index].name = name;
271 devices[internal_dev_index].info = info;
272 devices[internal_dev_index].num_channels = num_channels;
273 // Note: Purposefully does not overwrite held.
275 display_name = devices[internal_dev_index].display_name();
278 reset_device(internal_dev_index); // Restarts it if it is held (ie., we just replaced a dead card).
280 DeviceSpec spec{InputSourceType::ALSA_INPUT, internal_dev_index};
281 global_audio_mixer->set_device_parameters(spec, display_name, CardType::LIVE_CARD, /*num_channels=*/0, /*active=*/true); // Type and channels are ignored.
282 global_audio_mixer->trigger_state_changed_callback();
284 return ALSAPool::ProbeResult::SUCCESS;
287 void ALSAPool::unplug_device(unsigned card_index, unsigned dev_index)
290 snprintf(address, sizeof(address), "hw:%d,%d", card_index, dev_index);
291 for (unsigned i = 0; i < devices.size(); ++i) {
292 if (devices[i].state != Device::State::EMPTY &&
293 devices[i].state != Device::State::DEAD &&
294 devices[i].address == address) {
300 void ALSAPool::init()
302 inotify_thread = thread(&ALSAPool::inotify_thread_func, this);
306 void ALSAPool::inotify_thread_func()
308 pthread_setname_np(pthread_self(), "ALSA_Hotplug");
310 int inotify_fd = inotify_init();
311 if (inotify_fd == -1) {
312 perror("inotify_init()");
313 fprintf(stderr, "No hotplug of ALSA devices available.\n");
317 int watch_fd = inotify_add_watch(inotify_fd, "/dev/snd", IN_MOVE | IN_CREATE | IN_DELETE);
318 if (watch_fd == -1) {
319 perror("inotify_add_watch()");
320 fprintf(stderr, "No hotplug of ALSA devices available.\n");
325 int size = sizeof(inotify_event) + NAME_MAX + 1;
326 unique_ptr<char[]> buf(new char[size]);
327 while (!should_quit) {
329 fds[0].fd = inotify_fd;
330 fds[0].events = POLLIN;
332 fds[1].fd = should_quit_fd;
333 fds[1].events = POLLIN;
336 int ret = poll(fds, 2, -1);
338 if (errno == EINTR) {
341 perror("poll(inotify_fd)");
349 if (fds[1].revents) break; // should_quit_fd asserted.
351 ret = read(inotify_fd, buf.get(), size);
353 if (errno == EINTR) {
356 perror("read(inotify_fd)");
362 if (ret < int(sizeof(inotify_event))) {
363 fprintf(stderr, "inotify read unexpectedly returned %d, giving up hotplug of ALSA devices.\n",
370 for (int i = 0; i < ret; ) {
371 const inotify_event *event = reinterpret_cast<const inotify_event *>(&buf[i]);
372 i += sizeof(inotify_event) + event->len;
374 if (event->mask & IN_Q_OVERFLOW) {
375 fprintf(stderr, "WARNING: inotify overflowed, may lose ALSA hotplug events.\n");
378 unsigned card, device;
380 if (sscanf(event->name, "pcmC%uD%u%c", &card, &device, &type) == 3 && type == 'c') {
381 if (event->mask & (IN_MOVED_FROM | IN_DELETE)) {
382 printf("Deleted capture device: Card %u, device %u\n", card, device);
383 unplug_device(card, device);
385 if (event->mask & (IN_MOVED_TO | IN_CREATE)) {
386 printf("Adding capture device: Card %u, device %u\n", card, device);
387 probe_device_with_retry(card, device);
394 close(should_quit_fd);
397 void ALSAPool::reset_device(unsigned index)
399 lock_guard<mutex> lock(mu);
400 Device *device = &devices[index];
401 if (device->state == Device::State::DEAD) {
402 // Not running, and should not be started.
405 if (inputs[index] != nullptr) {
406 inputs[index]->stop_capture_thread();
409 inputs[index].reset();
411 // TODO: Put on a background thread instead of locking?
412 auto callback = bind(&AudioMixer::add_audio, global_audio_mixer, DeviceSpec{InputSourceType::ALSA_INPUT, index}, _1, _2, _3, _4);
413 inputs[index].reset(new ALSAInput(device->address.c_str(), OUTPUT_FREQUENCY, device->num_channels, callback, this, index));
414 inputs[index]->start_capture_thread();
416 device->input = inputs[index].get();
419 unsigned ALSAPool::get_capture_frequency(unsigned index)
421 lock_guard<mutex> lock(mu);
422 assert(devices[index].held);
423 if (devices[index].input)
424 return devices[index].input->get_sample_rate();
426 return OUTPUT_FREQUENCY;
429 ALSAPool::Device::State ALSAPool::get_card_state(unsigned index)
431 lock_guard<mutex> lock(mu);
432 assert(devices[index].held);
433 return devices[index].state;
436 void ALSAPool::set_card_state(unsigned index, ALSAPool::Device::State state)
439 lock_guard<mutex> lock(mu);
440 devices[index].state = state;
443 DeviceSpec spec{InputSourceType::ALSA_INPUT, index};
444 bool silence = (state != ALSAPool::Device::State::RUNNING);
445 while (!global_audio_mixer->silence_card(spec, silence))
447 global_audio_mixer->trigger_state_changed_callback();
450 unsigned ALSAPool::find_free_device_index(const string &name, const string &info, unsigned num_channels, const string &address)
452 // First try to find an exact match on a dead card.
453 for (unsigned i = 0; i < devices.size(); ++i) {
454 if (devices[i].state == Device::State::DEAD &&
455 devices[i].address == address &&
456 devices[i].name == name &&
457 devices[i].info == info &&
458 devices[i].num_channels == num_channels) {
459 devices[i].state = Device::State::READY;
464 // Then try to find a match on everything but the address
465 // (probably that devices were plugged back in a different order).
466 // If we have two cards that are equal, this might get them mixed up,
467 // but we don't have anything better.
468 for (unsigned i = 0; i < devices.size(); ++i) {
469 if (devices[i].state == Device::State::DEAD &&
470 devices[i].name == name &&
471 devices[i].info == info &&
472 devices[i].num_channels == num_channels) {
473 devices[i].state = Device::State::READY;
478 // OK, so we didn't find a match; see if there are any empty slots.
479 for (unsigned i = 0; i < devices.size(); ++i) {
480 if (devices[i].state == Device::State::EMPTY) {
481 devices[i].state = Device::State::READY;
482 devices[i].held = false;
487 // Failing that, we just insert the new device at the end.
489 new_dev.state = Device::State::READY;
490 new_dev.held = false;
491 devices.push_back(new_dev);
492 inputs.emplace_back(nullptr);
493 return devices.size() - 1;
496 unsigned ALSAPool::create_dead_card(const string &name, const string &info, unsigned num_channels)
498 lock_guard<mutex> lock(mu);
500 // See if there are any empty slots. If not, insert one at the end.
501 vector<Device>::iterator free_device =
502 find_if(devices.begin(), devices.end(),
503 [](const Device &device) { return device.state == Device::State::EMPTY; });
504 if (free_device == devices.end()) {
505 devices.push_back(Device());
506 inputs.emplace_back(nullptr);
507 free_device = devices.end() - 1;
510 free_device->state = Device::State::DEAD;
511 free_device->name = name;
512 free_device->info = info;
513 free_device->num_channels = num_channels;
514 free_device->held = true;
516 return distance(devices.begin(), free_device);
519 void ALSAPool::serialize_device(unsigned index, DeviceSpecProto *serialized)
521 lock_guard<mutex> lock(mu);
522 assert(index < devices.size());
523 assert(devices[index].held);
524 serialized->set_type(DeviceSpecProto::ALSA_INPUT);
525 serialized->set_index(index);
526 serialized->set_display_name(devices[index].display_name());
527 serialized->set_alsa_name(devices[index].name);
528 serialized->set_alsa_info(devices[index].info);
529 serialized->set_num_channels(devices[index].num_channels);
530 serialized->set_address(devices[index].address);
533 void ALSAPool::free_card(unsigned index)
535 DeviceSpec spec{InputSourceType::ALSA_INPUT, index};
536 while (!global_audio_mixer->silence_card(spec, true))
540 lock_guard<mutex> lock(mu);
541 if (devices[index].held) {
542 devices[index].state = Device::State::DEAD;
544 devices[index].state = Device::State::EMPTY;
545 inputs[index].reset();
547 while (!devices.empty() && devices.back().state == Device::State::EMPTY) {
553 global_audio_mixer->trigger_state_changed_callback();