#include <assert.h>
#include <limits.h>
#include <stdio.h>
+#include <sys/eventfd.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <algorithm>
using namespace std;
using namespace std::placeholders;
+ALSAPool::ALSAPool()
+{
+ should_quit_fd = eventfd(/*initval=*/0, /*flags=*/0);
+ assert(should_quit_fd != -1);
+}
+
ALSAPool::~ALSAPool()
{
for (Device &device : devices) {
device.input->stop_capture_thread();
}
}
+ should_quit = true;
+ const uint64_t one = 1;
+ write(should_quit_fd, &one, sizeof(one));
+ inotify_thread.join();
+
+ while (retry_threads_running > 0) {
+ this_thread::sleep_for(std::chrono::milliseconds(100));
+ }
}
std::vector<ALSAPool::Device> ALSAPool::get_devices()
// then start it ourselves.
fprintf(stderr, "Trying %s again in one second...\n", address);
add_device_tries_left[address] = num_retries;
+ ++retry_threads_running;
thread(&ALSAPool::probe_device_retry_thread_func, this, card_index, dev_index).detach();
}
// See if there are any retries left.
lock_guard<mutex> lock(add_device_mutex);
- if (!add_device_tries_left.count(address) ||
+ if (should_quit ||
+ !add_device_tries_left.count(address) ||
add_device_tries_left[address] == 0) {
add_device_tries_left.erase(address);
fprintf(stderr, "Giving up probe of %s.\n", address);
- return;
+ break;
}
// Seemingly there were. Give it a try (we still hold the mutex).
if (result == ProbeResult::SUCCESS) {
add_device_tries_left.erase(address);
fprintf(stderr, "Probe of %s succeeded.\n", address);
- return;
+ break;
} else if (result == ProbeResult::FAILURE || --add_device_tries_left[address] == 0) {
add_device_tries_left.erase(address);
fprintf(stderr, "Giving up probe of %s.\n", address);
- return;
+ break;
}
// Failed again.
fprintf(stderr, "Trying %s again in one second (%d tries left)...\n",
address, add_device_tries_left[address]);
}
+
+ --retry_threads_running;
}
ALSAPool::ProbeResult ALSAPool::probe_device_once(unsigned card_index, unsigned dev_index)
void ALSAPool::init()
{
- thread(&ALSAPool::inotify_thread_func, this).detach();
+ inotify_thread = thread(&ALSAPool::inotify_thread_func, this);
enumerate_devices();
}
int size = sizeof(inotify_event) + NAME_MAX + 1;
unique_ptr<char[]> buf(new char[size]);
- for ( ;; ) {
- int ret = read(inotify_fd, buf.get(), size);
+ while (!should_quit) {
+ pollfd fds[2];
+ fds[0].fd = inotify_fd;
+ fds[0].events = POLLIN;
+ fds[0].revents = 0;
+ fds[1].fd = should_quit_fd;
+ fds[1].events = POLLIN;
+ fds[1].revents = 0;
+
+ int ret = poll(fds, 2, -1);
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ perror("poll(inotify_fd)");
+ return;
+ }
+ }
+ if (ret == 0) {
+ continue;
+ }
+
+ if (fds[1].revents) break; // should_quit_fd asserted.
+
+ ret = read(inotify_fd, buf.get(), size);
+ if (ret == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else {
+ perror("read(inotify_fd)");
+ close(watch_fd);
+ close(inotify_fd);
+ return;
+ }
+ }
if (ret < int(sizeof(inotify_event))) {
fprintf(stderr, "inotify read unexpectedly returned %d, giving up hotplug of ALSA devices.\n",
int(ret));
}
}
}
+ close(watch_fd);
+ close(inotify_fd);
+ close(should_quit_fd);
}
void ALSAPool::reset_device(unsigned index)