diff options
author | Greg V <greg@unrelenting.technology> | 2020-04-02 19:18:29 +0300 |
---|---|---|
committer | PulseAudio Marge Bot <pulseaudio-maintainers@lists.freedesktop.org> | 2021-01-18 16:33:53 +0000 |
commit | ef8fa7c99752e0c404039a4c0f0c188d7033c431 (patch) | |
tree | cd7ba82c2d8373b5de8f873fece827aad8364810 | |
parent | a9d1afbefd489957d7e3250c239f768ca6b7711f (diff) |
oss: support hot-unplug on FreeBSD
Patch by Hans Petter Selasky <hselasky@FreeBSD.org>
ref: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=194727#c27
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/277>
-rw-r--r-- | src/modules/oss/module-oss.c | 58 | ||||
-rw-r--r-- | src/modules/oss/oss-util.c | 59 |
2 files changed, 66 insertions, 51 deletions
diff --git a/src/modules/oss/module-oss.c b/src/modules/oss/module-oss.c index a88c77e4d..048822c97 100644 --- a/src/modules/oss/module-oss.c +++ b/src/modules/oss/module-oss.c @@ -126,6 +126,8 @@ struct userdata { int nfrags, frag_size, orig_frag_size; + bool shutdown; + bool use_mmap; unsigned out_mmap_current, in_mmap_current; void *in_mmap, *out_mmap; @@ -843,14 +845,10 @@ static void sink_set_volume(pa_sink *s) { pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM)); if (u->mixer_devmask & SOUND_MASK_VOLUME) - if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume) >= 0) - return; + (void) pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume); if (u->mixer_devmask & SOUND_MASK_PCM) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume) >= 0) - return; - - pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + (void) pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume); } static void source_get_volume(pa_source *s) { @@ -858,7 +856,7 @@ static void source_get_volume(pa_source *s) { pa_assert_se(u = s->userdata); - pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + pa_assert(u->mixer_devmask & (SOUND_MASK_MIC|SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); if (u->mixer_devmask & SOUND_MASK_IGAIN) if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->real_volume) >= 0) @@ -868,6 +866,10 @@ static void source_get_volume(pa_source *s) { if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->real_volume) >= 0) return; + if (u->mixer_devmask & SOUND_MASK_MIC) + if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_MIC, &s->sample_spec, &s->real_volume) >= 0) + return; + pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno)); } @@ -876,17 +878,16 @@ static void source_set_volume(pa_source *s) { pa_assert_se(u = s->userdata); - pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); + pa_assert(u->mixer_devmask & (SOUND_MASK_MIC|SOUND_MASK_IGAIN|SOUND_MASK_RECLEV)); if (u->mixer_devmask & SOUND_MASK_IGAIN) - if (pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->real_volume) >= 0) - return; + (void) pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->real_volume); if (u->mixer_devmask & SOUND_MASK_RECLEV) - if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->real_volume) >= 0) - return; + (void) pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->real_volume); - pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno)); + if (u->mixer_devmask & SOUND_MASK_MIC) + (void) pa_oss_set_volume(u->mixer_fd, SOUND_MIXER_WRITE_MIC, &s->sample_spec, &s->real_volume); } static void thread_func(void *userdata) { @@ -1127,15 +1128,22 @@ static void thread_func(void *userdata) { pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL); pollfd->events = (short) (((u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0) | - ((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0)); + ((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0) | + POLLHUP); } + /* set a watchdog timeout of one second */ + pa_rtpoll_set_timer_relative(u->rtpoll, 1000000); + /* Hmm, nothing to do. Let's sleep */ - if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) + if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) { goto fail; + } - if (ret == 0) - goto finish; + /* check for shutdown */ + if (u->shutdown) { + goto fail; + } if (u->rtpoll_item) { struct pollfd *pollfd; @@ -1150,6 +1158,16 @@ static void thread_func(void *userdata) { revents = pollfd->revents; } else revents = 0; + + /* check for mixer shutdown, if any */ + if ((revents & (POLLOUT | POLLIN)) == 0) { + int mixer_fd = u->mixer_fd; + int devmask; + if (mixer_fd > -1 && ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) { + pa_log("Mixer shutdown."); + goto fail; + } + } } fail: @@ -1157,9 +1175,6 @@ fail: * processing messages until we received PA_MESSAGE_SHUTDOWN */ pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL); pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); - -finish: - pa_log_debug("Thread shutting down"); } int pa__init(pa_module*m) { @@ -1448,7 +1463,7 @@ int pa__init(pa_module*m) { do_close = false; } - if (u->source && (u->mixer_devmask & (SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) { + if (u->source && (u->mixer_devmask & (SOUND_MASK_MIC|SOUND_MASK_RECLEV|SOUND_MASK_IGAIN))) { pa_log_debug("Found hardware mixer track for recording."); pa_source_set_get_volume_callback(u->source, source_get_volume); pa_source_set_set_volume_callback(u->source, source_set_volume); @@ -1533,6 +1548,7 @@ void pa__done(pa_module*m) { pa_source_unlink(u->source); if (u->thread) { + u->shutdown = true; pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); pa_thread_free(u->thread); } diff --git a/src/modules/oss/oss-util.c b/src/modules/oss/oss-util.c index 4deef9f16..f2ce42a26 100644 --- a/src/modules/oss/oss-util.c +++ b/src/modules/oss/oss-util.c @@ -40,6 +40,7 @@ #include "oss-util.h" int pa_oss_open(const char *device, int *mode, int* pcaps) { + static const int nonblock_io = 1; int fd = -1; int caps; char *t; @@ -89,6 +90,10 @@ int pa_oss_open(const char *device, int *mode, int* pcaps) { } success: + if (ioctl(fd, FIONBIO, &nonblock_io) < 0) { + pa_log("FIONBIO: %s", pa_cstrerror(errno)); + goto fail; + } t = pa_sprintf_malloc( "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", @@ -295,41 +300,35 @@ int pa_oss_set_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, con } static int get_device_number(const char *dev) { - const char *p, *e; + const char *p; + const char *e; char *rp = NULL; - int r; + int r = -1; if (!(p = rp = pa_readlink(dev))) { -#ifdef ENOLINK - if (errno != EINVAL && errno != ENOLINK) { -#else - if (errno != EINVAL) { -#endif - r = -1; - goto finish; - } - + if (errno != EINVAL && errno != ENOLINK) + return -2; p = dev; } - if ((e = strrchr(p, '/'))) - p = e+1; - - if (p == 0) { - r = 0; - goto finish; - } - - p = strchr(p, 0) -1; - - if (*p >= '0' && *p <= '9') { - r = *p - '0'; - goto finish; + /* find the last forward slash */ + while ((e = strrchr(p, '/'))) + p = e + 1; + + /* collect unit number at end, if any */ + while (*p) { + if (*p >= '0' && *p <= '9') { + if (r < 0) + r = 0; + else + r *= 10; + r += *p - '0'; + } else { + r = -1; + } + p++; } - r = -1; - -finish: pa_xfree(rp); return r; } @@ -339,7 +338,7 @@ int pa_oss_get_hw_description(const char *dev, char *name, size_t l) { int n, r = -1; int b = 0; - if ((n = get_device_number(dev)) < 0) + if ((n = get_device_number(dev)) == -2) return -1; if (!(f = pa_fopen_cloexec("/dev/sndstat", "r")) && @@ -405,10 +404,10 @@ int pa_oss_open_mixer_for_device(const char *device) { char *fn; int fd; - if ((n = get_device_number(device)) < 0) + if ((n = get_device_number(device)) == -2) return -1; - if (n == 0) + if (n == -1) if ((fd = open_mixer("/dev/mixer")) >= 0) return fd; |