git: 3bc8803e5c4a - main - audio/pulseaudio: Fix for detachable USB audio devices.

From: Hans Petter Selasky <hselasky_at_FreeBSD.org>
Date: Wed, 25 May 2022 09:00:36 UTC
The branch main has been updated by hselasky:

URL: https://cgit.FreeBSD.org/ports/commit/?id=3bc8803e5c4a96b60ffe5fa6887e2b73e0df7756

commit 3bc8803e5c4a96b60ffe5fa6887e2b73e0df7756
Author:     Hans Petter Selasky <hselasky@FreeBSD.org>
AuthorDate: 2022-05-25 08:39:40 +0000
Commit:     Hans Petter Selasky <hselasky@FreeBSD.org>
CommitDate: 2022-05-25 08:58:56 +0000

    audio/pulseaudio: Fix for detachable USB audio devices.
    
    Make sure the pulseaudio OSS module does not keep the mixer device opened
    forever. Instead open and close the mixer device for every access. Also
    fix some bad code mixing get- and set- volume while at it.
    
    Reported by: several
    PR: 194727
    Approved by: pi (implicit)
---
 audio/pulseaudio/Makefile                          |   2 +-
 .../files/patch-src_modules_oss_module-oss.c       | 256 ++++++++++++++++++++-
 2 files changed, 255 insertions(+), 3 deletions(-)

diff --git a/audio/pulseaudio/Makefile b/audio/pulseaudio/Makefile
index d88ae8c9776d..3b7f58dd198d 100644
--- a/audio/pulseaudio/Makefile
+++ b/audio/pulseaudio/Makefile
@@ -5,7 +5,7 @@
 
 PORTNAME=	pulseaudio
 DISTVERSION=	14.2
-PORTREVISION=	3
+PORTREVISION=	4
 CATEGORIES=	audio
 MASTER_SITES=	https://freedesktop.org/software/pulseaudio/releases/
 
diff --git a/audio/pulseaudio/files/patch-src_modules_oss_module-oss.c b/audio/pulseaudio/files/patch-src_modules_oss_module-oss.c
index f7a54f7cc1f0..b077752ac2e2 100644
--- a/audio/pulseaudio/files/patch-src_modules_oss_module-oss.c
+++ b/audio/pulseaudio/files/patch-src_modules_oss_module-oss.c
@@ -1,6 +1,191 @@
---- src/modules/oss/module-oss.c.orig	2018-05-07 14:30:52 UTC
+--- src/modules/oss/module-oss.c.orig	2021-01-16 17:26:36 UTC
 +++ src/modules/oss/module-oss.c
-@@ -1235,10 +1235,14 @@ int pa__init(pa_module*m) {
+@@ -121,9 +121,6 @@ struct userdata {
+     int fd;
+     int mode;
+ 
+-    int mixer_fd;
+-    int mixer_devmask;
+-
+     int nfrags, frag_size, orig_frag_size;
+ 
+     bool use_mmap;
+@@ -817,76 +814,146 @@ static int source_set_state_in_io_thread_cb(pa_source 
+     return 0;
+ }
+ 
++static int open_mixer(struct userdata *u, int *p_devmask) {
++    int mixer_fd;
++
++    mixer_fd = pa_oss_open_mixer_for_device(u->device_name);
++    if (mixer_fd < 0)
++        return (mixer_fd);
++
++    if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, p_devmask) < 0) {
++        pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
++        pa_close(mixer_fd);
++        return (-1);
++    }
++    return (mixer_fd);
++}
++
++static void oss_get_dummy_volume(const pa_sample_spec *ss, pa_cvolume *volume) {
++    char cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
++    unsigned vol;
++
++    pa_assert(ss);
++    pa_assert(volume);
++
++    vol = 100 | (100 << 8);
++
++    pa_cvolume_reset(volume, ss->channels);
++
++    volume->values[0] = PA_CLAMP_VOLUME(((vol & 0xFF) * PA_VOLUME_NORM) / 100);
++
++    if (volume->channels >= 2)
++        volume->values[1] = PA_CLAMP_VOLUME((((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100);
++
++    pa_log_debug("Read dummy settings: %s", pa_cvolume_snprint_verbose(cv, sizeof(cv), volume, NULL, false));
++}
++
+ static void sink_get_volume(pa_sink *s) {
+     struct userdata *u;
+ 
++    int mixer_fd;
++    int mixer_devmask;
++
+     pa_assert_se(u = s->userdata);
+ 
+-    pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
++    mixer_fd = open_mixer(u, &mixer_devmask);
++    if (mixer_fd < 0) {
++        oss_get_dummy_volume(&s->sample_spec, &s->real_volume);
++        return;
++    }
+ 
+-    if (u->mixer_devmask & SOUND_MASK_VOLUME)
+-        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
+-            return;
++    if (mixer_devmask & SOUND_MASK_VOLUME)
++        if (pa_oss_get_volume(mixer_fd, SOUND_MIXER_READ_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
++	    goto done;
+ 
+-    if (u->mixer_devmask & SOUND_MASK_PCM)
+-        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->real_volume) >= 0)
+-            return;
++    if (mixer_devmask & SOUND_MASK_PCM)
++        if (pa_oss_get_volume(mixer_fd, SOUND_MIXER_READ_PCM, &s->sample_spec, &s->real_volume) >= 0)
++            goto done;
+ 
++    oss_get_dummy_volume(&s->sample_spec, &s->real_volume);
++
+     pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
++done:
++    pa_close(mixer_fd);
+ }
+ 
+ static void sink_set_volume(pa_sink *s) {
+     struct userdata *u;
+ 
++    int mixer_fd;
++    int mixer_devmask;
++
+     pa_assert_se(u = s->userdata);
+ 
+-    pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
++    mixer_fd = open_mixer(u, &mixer_devmask);
++    if (mixer_fd < 0)
++        return;
+ 
+-    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;
++    if (mixer_devmask & SOUND_MASK_VOLUME)
++        if (pa_oss_set_volume(mixer_fd, SOUND_MIXER_WRITE_VOLUME, &s->sample_spec, &s->real_volume) >= 0)
++            goto done;
+ 
+-    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;
++    if (mixer_devmask & SOUND_MASK_PCM)
++        if (pa_oss_set_volume(mixer_fd, SOUND_MIXER_WRITE_PCM, &s->sample_spec, &s->real_volume) >= 0)
++            goto done;
+ 
+     pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
++done:
++    pa_close(mixer_fd);
+ }
+ 
+ static void source_get_volume(pa_source *s) {
+     struct userdata *u;
+ 
++    int mixer_fd;
++    int mixer_devmask;
++
+     pa_assert_se(u = s->userdata);
+ 
+-    pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
++    mixer_fd = open_mixer(u, &mixer_devmask);
++    if (mixer_fd < 0) {
++      oss_get_dummy_volume(&s->sample_spec, &s->real_volume);
++      return;
++    }
+ 
+-    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)
+-            return;
++    if (mixer_devmask & SOUND_MASK_IGAIN)
++        if (pa_oss_get_volume(mixer_fd, SOUND_MIXER_READ_IGAIN, &s->sample_spec, &s->real_volume) >= 0)
++                goto done;
+ 
+-    if (u->mixer_devmask & SOUND_MASK_RECLEV)
+-        if (pa_oss_get_volume(u->mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->real_volume) >= 0)
+-            return;
++    if (mixer_devmask & SOUND_MASK_RECLEV)
++        if (pa_oss_get_volume(mixer_fd, SOUND_MIXER_READ_RECLEV, &s->sample_spec, &s->real_volume) >= 0)
++                goto done;
+ 
++    oss_get_dummy_volume(&s->sample_spec, &s->real_volume);
++
+     pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
++done:
++    pa_close(mixer_fd);
+ }
+ 
+ static void source_set_volume(pa_source *s) {
+     struct userdata *u;
+ 
++    int mixer_fd;
++    int mixer_devmask;
++
+     pa_assert_se(u = s->userdata);
+ 
+-    pa_assert(u->mixer_devmask & (SOUND_MASK_IGAIN|SOUND_MASK_RECLEV));
++    mixer_fd = open_mixer(u, &mixer_devmask);
++    if (mixer_fd < 0)
++        return;
+ 
+-    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;
++    if (mixer_devmask & SOUND_MASK_IGAIN)
++        if (pa_oss_set_volume(mixer_fd, SOUND_MIXER_WRITE_IGAIN, &s->sample_spec, &s->real_volume) >= 0)
++            goto done;
+ 
+-    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;
++    if (mixer_devmask & SOUND_MASK_RECLEV)
++        if (pa_oss_set_volume(mixer_fd, SOUND_MIXER_WRITE_RECLEV, &s->sample_spec, &s->real_volume) >= 0)
++            goto done;
+ 
+     pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
++done:
++    pa_close(mixer_fd);
+ }
+ 
+ static void thread_func(void *userdata) {
+@@ -1235,10 +1302,14 @@ int pa__init(pa_module*m) {
          use_mmap = false;
      }
  
@@ -15,3 +200,70 @@
  
      if (pa_oss_get_hw_description(dev, hwdesc, sizeof(hwdesc)) >= 0)
          pa_log_info("Hardware name is '%s'.", hwdesc);
+@@ -1266,8 +1337,6 @@ int pa__init(pa_module*m) {
+     u->module = m;
+     m->userdata = u;
+     u->fd = fd;
+-    u->mixer_fd = -1;
+-    u->mixer_devmask = 0;
+     u->use_getospace = u->use_getispace = true;
+     u->use_getodelay = true;
+     u->mode = mode;
+@@ -1438,36 +1507,19 @@ int pa__init(pa_module*m) {
+             u->out_mmap_memblocks = pa_xnew0(pa_memblock*, u->out_nfrags);
+     }
+ 
+-    if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
+-        bool do_close = true;
+-
+-        if (ioctl(u->mixer_fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
+-            pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
+-        else {
+-            if (u->sink && (u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM))) {
+-                pa_log_debug("Found hardware mixer track for playback.");
+-                pa_sink_set_get_volume_callback(u->sink, sink_get_volume);
+-                pa_sink_set_set_volume_callback(u->sink, sink_set_volume);
+-                u->sink->n_volume_steps = 101;
+-                do_close = false;
+-            }
+-
+-            if (u->source && (u->mixer_devmask & (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);
+-                u->source->n_volume_steps = 101;
+-                do_close = false;
+-            }
+-        }
+-
+-        if (do_close) {
+-            pa_close(u->mixer_fd);
+-            u->mixer_fd = -1;
+-            u->mixer_devmask = 0;
+-        }
++    if (u->sink) {
++        pa_log_debug("Found hardware mixer track for playback.");
++        pa_sink_set_get_volume_callback(u->sink, sink_get_volume);
++        pa_sink_set_set_volume_callback(u->sink, sink_set_volume);
++        u->sink->n_volume_steps = 101;
+     }
+ 
++    if (u->source) {
++        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);
++        u->source->n_volume_steps = 101;
++    }
+ go_on:
+ 
+     pa_assert(u->source || u->sink);
+@@ -1582,9 +1634,6 @@ void pa__done(pa_module*m) {
+ 
+     if (u->fd >= 0)
+         pa_close(u->fd);
+-
+-    if (u->mixer_fd >= 0)
+-        pa_close(u->mixer_fd);
+ 
+     pa_xfree(u->device_name);
+