From 7a714298c18e917306a5efae0fa09a801b09d5ac Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Aug 2015 21:45:22 -0700 Subject: [PATCH] add soundio_force_device_scan API --- example/sio_list_devices.c | 12 +++++++++++- soundio/soundio.h | 16 ++++++++++++++++ src/alsa.cpp | 6 ++++++ src/coreaudio.cpp | 7 +++++++ src/dummy.cpp | 5 +++++ src/jack.cpp | 11 +++++++++++ src/pulseaudio.cpp | 17 +++++++++++++++-- src/soundio.cpp | 5 +++++ src/soundio.hpp | 1 + src/wasapi.cpp | 13 ++++++++----- 10 files changed, 85 insertions(+), 8 deletions(-) diff --git a/example/sio_list_devices.c b/example/sio_list_devices.c index 72a7f23..4c5a3ad 100644 --- a/example/sio_list_devices.c +++ b/example/sio_list_devices.c @@ -14,7 +14,11 @@ // list or keep a watch on audio devices static int usage(char *exe) { - fprintf(stderr, "Usage: %s [--watch] [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n", exe); + fprintf(stderr, "Usage: %s [options]\n" + "Options:\n" + " [--watch]\n" + " [--backend dummy|alsa|pulseaudio|jack|coreaudio|wasapi]\n" + " [--short]\n", exe); return 1; } @@ -29,10 +33,14 @@ static void print_channel_layout(const struct SoundIoChannelLayout *layout) { } } +static bool short_output = false; + static void print_device(struct SoundIoDevice *device, bool is_default) { const char *default_str = is_default ? " (default)" : ""; const char *raw_str = device->is_raw ? " (raw)" : ""; fprintf(stderr, "%s%s%s\n", device->name, default_str, raw_str); + if (short_output) + return; fprintf(stderr, " id: %s\n", device->id); if (device->probe_error) { @@ -114,6 +122,8 @@ int main(int argc, char **argv) { char *arg = argv[i]; if (strcmp("--watch", arg) == 0) { watch = true; + } else if (strcmp("--short", arg) == 0) { + short_output = true; } else if (arg[0] == '-' && arg[1] == '-') { i += 1; if (i >= argc) { diff --git a/soundio/soundio.h b/soundio/soundio.h index dad4aea..0982aa5 100644 --- a/soundio/soundio.h +++ b/soundio/soundio.h @@ -725,6 +725,22 @@ SOUNDIO_EXPORT void soundio_wait_events(struct SoundIo *soundio); SOUNDIO_EXPORT void soundio_wakeup(struct SoundIo *soundio); +/// If necessary you can manually trigger a device rescan. Normally you will +/// not ever have to call this function, as libsoundio listens to system events +/// for device changes and responds to them by rescanning devices and preparing +/// the new device information for you to be atomically replaced when you call +/// ::soundio_flush_events. However you might run into cases where you want to +/// force trigger a device rescan, for example if an ALSA device has a +/// SoundIoDevice::probe_error. +/// +/// After you call this you still have to use ::soundio_flush_events or +/// ::soundio_wait_events and then wait for the +/// SoundIo::on_devices_change callback. +/// +/// This can be called from any thread context except for +/// SoundIoOutStream::write_callback and SoundIoInStream::read_callback +SOUNDIO_EXPORT void soundio_force_device_scan(struct SoundIo *soundio); + // Channel Layouts diff --git a/src/alsa.cpp b/src/alsa.cpp index e529885..d75de3e 100644 --- a/src/alsa.cpp +++ b/src/alsa.cpp @@ -913,6 +913,11 @@ static void wakeup_alsa(SoundIoPrivate *si) { soundio_os_mutex_unlock(sia->mutex); } +static void force_device_scan_alsa(SoundIoPrivate *si) { + SoundIoAlsa *sia = &si->backend_data.alsa; + wakeup_device_poll(sia); +} + static void outstream_destroy_alsa(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { SoundIoOutStreamAlsa *osa = &os->backend_data.alsa; @@ -1771,6 +1776,7 @@ int soundio_alsa_init(SoundIoPrivate *si) { si->flush_events = flush_events_alsa; si->wait_events = wait_events_alsa; si->wakeup = wakeup_alsa; + si->force_device_scan = force_device_scan_alsa; si->outstream_open = outstream_open_alsa; si->outstream_destroy = outstream_destroy_alsa; diff --git a/src/coreaudio.cpp b/src/coreaudio.cpp index 0ceb39c..2be7d0c 100644 --- a/src/coreaudio.cpp +++ b/src/coreaudio.cpp @@ -820,6 +820,12 @@ static void wakeup_ca(struct SoundIoPrivate *si) { soundio_os_cond_signal(sica->cond, nullptr); } +static void force_device_scan_ca(struct SoundIoPrivate *si) { + SoundIoCoreAudio *sica = &si->backend_data.coreaudio; + sica->device_scan_queued.store(true); + soundio_os_cond_signal(sica->scan_devices_cond, nullptr); +} + static void device_thread_run(void *arg) { SoundIoPrivate *si = (SoundIoPrivate *)arg; SoundIo *soundio = &si->pub; @@ -1365,6 +1371,7 @@ int soundio_coreaudio_init(SoundIoPrivate *si) { si->flush_events = flush_events_ca; si->wait_events = wait_events_ca; si->wakeup = wakeup_ca; + si->force_device_scan = force_device_scan_ca; si->outstream_open = outstream_open_ca; si->outstream_destroy = outstream_destroy_ca; diff --git a/src/dummy.cpp b/src/dummy.cpp index 2b633c5..310b0dd 100644 --- a/src/dummy.cpp +++ b/src/dummy.cpp @@ -129,6 +129,10 @@ static void wakeup_dummy(SoundIoPrivate *si) { soundio_os_cond_signal(sid->cond, nullptr); } +static void force_device_scan_dummy(SoundIoPrivate *si) { + // nothing to do; dummy devices never change +} + static void outstream_destroy_dummy(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { SoundIoOutStreamDummy *osd = &os->backend_data.dummy; @@ -508,6 +512,7 @@ int soundio_dummy_init(SoundIoPrivate *si) { si->flush_events = flush_events_dummy; si->wait_events = wait_events_dummy; si->wakeup = wakeup_dummy; + si->force_device_scan = force_device_scan_dummy; si->outstream_open = outstream_open_dummy; si->outstream_destroy = outstream_destroy_dummy; diff --git a/src/jack.cpp b/src/jack.cpp index 3fd45cc..bf5c187 100644 --- a/src/jack.cpp +++ b/src/jack.cpp @@ -339,6 +339,16 @@ static void wakeup_jack(struct SoundIoPrivate *si) { soundio_os_mutex_unlock(sij->mutex); } +static void force_device_scan_jack(struct SoundIoPrivate *si) { + SoundIo *soundio = &si->pub; + SoundIoJack *sij = &si->backend_data.jack; + sij->refresh_devices_flag.clear(); + soundio_os_mutex_lock(sij->mutex); + soundio_os_cond_signal(sij->cond, sij->mutex); + soundio->on_events_signal(soundio); + soundio_os_mutex_unlock(sij->mutex); +} + static int outstream_process_callback(jack_nframes_t nframes, void *arg) { SoundIoOutStreamPrivate *os = (SoundIoOutStreamPrivate *)arg; SoundIoOutStreamJack *osj = &os->backend_data.jack; @@ -892,6 +902,7 @@ int soundio_jack_init(struct SoundIoPrivate *si) { si->flush_events = flush_events_jack; si->wait_events = wait_events_jack; si->wakeup = wakeup_jack; + si->force_device_scan = force_device_scan_jack; si->outstream_open = outstream_open_jack; si->outstream_destroy = outstream_destroy_jack; diff --git a/src/pulseaudio.cpp b/src/pulseaudio.cpp index 2cc8b26..81cf4a4 100644 --- a/src/pulseaudio.cpp +++ b/src/pulseaudio.cpp @@ -491,9 +491,21 @@ static void wait_events_pa(SoundIoPrivate *si) { my_flush_events(si, true); } -static void wakeup(SoundIoPrivate *si) { +static void wakeup_pa(SoundIoPrivate *si) { SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; + pa_threaded_mainloop_lock(sipa->main_loop); pa_threaded_mainloop_signal(sipa->main_loop, 0); + pa_threaded_mainloop_unlock(sipa->main_loop); +} + +static void force_device_scan_pa(SoundIoPrivate *si) { + SoundIo *soundio = &si->pub; + SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; + pa_threaded_mainloop_lock(sipa->main_loop); + sipa->device_scan_queued = true; + pa_threaded_mainloop_signal(sipa->main_loop, 0); + soundio->on_events_signal(soundio); + pa_threaded_mainloop_unlock(sipa->main_loop); } static pa_sample_format_t to_pulseaudio_format(SoundIoFormat format) { @@ -1062,7 +1074,8 @@ int soundio_pulseaudio_init(SoundIoPrivate *si) { si->destroy = destroy_pa; si->flush_events = flush_events_pa; si->wait_events = wait_events_pa; - si->wakeup = wakeup; + si->wakeup = wakeup_pa; + si->force_device_scan = force_device_scan_pa; si->outstream_open = outstream_open_pa; si->outstream_destroy = outstream_destroy_pa; diff --git a/src/soundio.cpp b/src/soundio.cpp index 9df0535..ce47e76 100644 --- a/src/soundio.cpp +++ b/src/soundio.cpp @@ -417,6 +417,11 @@ void soundio_wakeup(struct SoundIo *soundio) { si->wakeup(si); } +void soundio_force_device_scan(struct SoundIo *soundio) { + SoundIoPrivate *si = (SoundIoPrivate *)soundio; + si->force_device_scan(si); +} + int soundio_outstream_begin_write(struct SoundIoOutStream *outstream, SoundIoChannelArea **areas, int *frame_count) { diff --git a/src/soundio.hpp b/src/soundio.hpp index a894ebd..a26cb5d 100644 --- a/src/soundio.hpp +++ b/src/soundio.hpp @@ -137,6 +137,7 @@ struct SoundIoPrivate { void (*flush_events)(struct SoundIoPrivate *); void (*wait_events)(struct SoundIoPrivate *); void (*wakeup)(struct SoundIoPrivate *); + void (*force_device_scan)(struct SoundIoPrivate *); int (*outstream_open)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *); void (*outstream_destroy)(struct SoundIoPrivate *, struct SoundIoOutStreamPrivate *); diff --git a/src/wasapi.cpp b/src/wasapi.cpp index ebceb4c..ea12254 100644 --- a/src/wasapi.cpp +++ b/src/wasapi.cpp @@ -1017,6 +1017,12 @@ static void wakeup_wasapi(struct SoundIoPrivate *si) { soundio_os_cond_signal(siw->cond, siw->mutex); } +static void force_device_scan_wasapi(struct SoundIoPrivate *si) { + SoundIoWasapi *siw = &si->backend_data.wasapi; + siw->device_scan_queued.store(true); + soundio_os_cond_signal(siw->scan_devices_cond, nullptr); +} + static void outstream_thread_deinit(SoundIoPrivate *si, SoundIoOutStreamPrivate *os) { SoundIoOutStreamWasapi *osw = &os->backend_data.wasapi; @@ -1903,11 +1909,7 @@ static STDMETHODIMP_(ULONG) soundio_MMNotificationClient_Release(IMMNotification static HRESULT queue_device_scan(IMMNotificationClient *client) { SoundIoPrivate *si = soundio_MMNotificationClient_si(client); - SoundIoWasapi *siw = &si->backend_data.wasapi; - - siw->device_scan_queued.store(true); - soundio_os_cond_signal(siw->scan_devices_cond, nullptr); - + force_device_scan_wasapi(si); return S_OK; } @@ -1986,6 +1988,7 @@ int soundio_wasapi_init(SoundIoPrivate *si) { si->flush_events = flush_events_wasapi; si->wait_events = wait_events_wasapi; si->wakeup = wakeup_wasapi; + si->force_device_scan = force_device_scan_wasapi; si->outstream_open = outstream_open_wasapi; si->outstream_destroy = outstream_destroy_wasapi;