git: 9aac27599aca - main - mixer(8): Implement hot-swapping
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 24 Aug 2024 12:09:13 UTC
The branch main has been updated by christos: URL: https://cgit.FreeBSD.org/src/commit/?id=9aac27599acaffa21ff69c5be8a2d71d29cc3d6b commit 9aac27599acaffa21ff69c5be8a2d71d29cc3d6b Author: Christos Margiolis <christos@FreeBSD.org> AuthorDate: 2024-08-24 12:07:35 +0000 Commit: Christos Margiolis <christos@FreeBSD.org> CommitDate: 2024-08-24 12:07:35 +0000 mixer(8): Implement hot-swapping Introduce a -V option, which can be used alongside -d (default unit change), in order to hot-swap devices (i.e switch to them on the fly without needing to restart the track), in case virtual_oss(8) exists and is running. Sponsored by: The FreeBSD Foundation MFC after: 2 days Reviewed by: dev_submerge.ch Differential Revision: https://reviews.freebsd.org/D46253 --- usr.sbin/mixer/mixer.8 | 75 +++++++++++++++++++++++++++++++++++++++++++--- usr.sbin/mixer/mixer.c | 81 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 145 insertions(+), 11 deletions(-) diff --git a/usr.sbin/mixer/mixer.8 b/usr.sbin/mixer/mixer.8 index 75c6a81e3a55..819d8ae73ab1 100644 --- a/usr.sbin/mixer/mixer.8 +++ b/usr.sbin/mixer/mixer.8 @@ -19,7 +19,7 @@ .\" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN .\" THE SOFTWARE. .\" -.Dd February 8, 2024 +.Dd August 14, 2024 .Dt MIXER 8 .Os .Sh NAME @@ -28,7 +28,7 @@ .Sh SYNOPSIS .Nm .Op Fl f Ar device -.Op Fl d Ar pcmN | N +.Op Fl d Ar pcmN | N Op Fl V Ar voss_device:mode .Op Fl os .Op Ar dev Ns Op Cm \&. Ns Ar control Ns Op Cm \&= Ns Ar value .Ar ... @@ -43,7 +43,7 @@ The utility is used to set and display soundcard mixer device controls. .Pp The options are as follows: -.Bl -tag -width "-d pcmN | N" +.Bl -tag -width "-V voss_device:mode" .It Fl a Print the values for all mixer devices available in the system .Pq see Sx FILES . @@ -54,6 +54,30 @@ where N is the unit number (e.g for pcm0, the unit number is 0). See .Sx EXAMPLES on how to list all available audio devices in the system. +.Pp +There is also the possibility of hot-swapping to the new default device if +.Xr virtual_oss 8 +exists in the system and is running, in which case the +.Fl V +option needs to be specified as well. +.Pp +Hot-swapping generally cannot happen with plain +.Xr sound 4 , +so the user has to restart the track in order to get sound coming out of the +new default device. +This is because applications usually open a device at the start of the track +and do not check for default device changes, in order to open the new device +mid-track. +.Xr virtual_oss 8 , +on the other hand, can do hot-swapping, because it creates a virtual device for +applications to open, and then does all the necessary routing and conversions +to the appropriate device(s). +.Pp +Note that hot-swapping will work only for applications that are using +.Xr virtual_oss 8 +devices, and not plain +.Xr sound 4 +ones. .It Fl f Ar device Open .Ar device @@ -66,6 +90,33 @@ Print mixer values in a format suitable for use inside scripts. The mixer's header (name, audio card name, ...) will not be printed. .It Fl s Print only the recording source(s) of the mixer device. +.It Fl V Ar voss_device:mode +Specify a +.Xr virtual_oss 8 +control device, as well as a mode (see below), in order to hot-swap devices. +This option is meant to only be used in combination with the +.Fl d +option. +.Pp +The available modes are as follows: +.Bl -column play +.It Sy Mode Ta Sy Action +.It all Ta Playback and recording +.It play Ta Playback +.It rec Ta Recording +.El +.Pp +The +.Pa mode +part is needed, so that +.Nm +will not accidentally hot-swap both the recording and playback device in +.Xr virtual_oss 8 , +if only one direction is to be hot-swapped. +.Pp +See +.Sx EXAMPLES +on how to use this option. .El .Pp The list of mixer devices that may be modified are: @@ -273,10 +324,26 @@ $ mixer -f /dev/mixer0 -o > info \&... $ mixer -f /dev/mixer0 `cat info` .Ed +.Pp +Suppose +.Xr virtual_oss 8 +is running with +.Pa /dev/vdsp.ctl +as its control device, and +.Pa pcm0 +as the playback device. +Change the default device to +.Pa pcm1 , +and hot-swap to it for both recording and playback in +.Xr virtual_oss 8 : +.Bd -literal -offset indent +$ mixer -d pcm1 -V /dev/vdsp.ctl:all +.Ed .Sh SEE ALSO .Xr mixer 3 , .Xr sound 4 , -.Xr sysctl 8 +.Xr sysctl 8 , +.Xr virtual_oss 8 .Sh HISTORY The .Nm diff --git a/usr.sbin/mixer/mixer.c b/usr.sbin/mixer/mixer.c index 109d3ad09bc5..468130ddaa88 100644 --- a/usr.sbin/mixer/mixer.c +++ b/usr.sbin/mixer/mixer.c @@ -20,6 +20,9 @@ * THE SOFTWARE. */ +#include <sys/sysctl.h> +#include <sys/wait.h> + #include <err.h> #include <errno.h> #include <mixer.h> @@ -40,7 +43,7 @@ static void printall(struct mixer *, int); static void printminfo(struct mixer *, int); static void printdev(struct mixer *, int); static void printrecsrc(struct mixer *, int); /* XXX: change name */ -static int set_dunit(struct mixer *, int); +static int set_dunit(struct mixer *, int, char *); /* Control handlers */ static int mod_volume(struct mix_dev *, void *); static int mod_mute(struct mix_dev *, void *); @@ -54,13 +57,13 @@ main(int argc, char *argv[]) { struct mixer *m; mix_ctl_t *cp; - char *name = NULL, buf[NAME_MAX]; + char *name = NULL, buf[NAME_MAX], *vctl = NULL; char *p, *q, *devstr, *ctlstr, *valstr = NULL; int dunit, i, n, pall = 1, shorthand; int aflag = 0, dflag = 0, oflag = 0, sflag = 0; int ch; - while ((ch = getopt(argc, argv, "ad:f:hos")) != -1) { + while ((ch = getopt(argc, argv, "ad:f:hosV:")) != -1) { switch (ch) { case 'a': aflag = 1; @@ -83,6 +86,9 @@ main(int argc, char *argv[]) case 's': sflag = 1; break; + case 'V': + vctl = optarg; + break; case 'h': /* FALLTHROUGH */ case '?': default: @@ -119,7 +125,7 @@ main(int argc, char *argv[]) initctls(m); if (dflag) { - if (set_dunit(m, dunit) < 0) + if (set_dunit(m, dunit, vctl) < 0) goto parse; else { /* @@ -209,7 +215,8 @@ next: static void __dead2 usage(void) { - fprintf(stderr, "usage: %1$s [-f device] [-d pcmN | N] [-os] [dev[.control[=value]]] ...\n" + fprintf(stderr, "usage: %1$s [-f device] [-d pcmN | N " + "[-V voss_device:mode]] [-os] [dev[.control[=value]]] ...\n" " %1$s [-os] -a\n" " %1$s -h\n", getprogname()); exit(1); @@ -322,9 +329,32 @@ printrecsrc(struct mixer *m, int oflag) } static int -set_dunit(struct mixer *m, int dunit) +set_dunit(struct mixer *m, int dunit, char *vctl) { - int n; + const char *opt; + char *dev, *mode; + char buf[32]; + size_t size; + int n, rc; + + /* + * Issue warning in case of hw.snd.basename_clone being unset. Omit the + * check and warning if the -V flag is used, since the user is most + * likely to be aware of this, and the warning might be confusing. + */ + if (vctl == NULL) { + size = sizeof(int); + if (sysctlbyname("hw.snd.basename_clone", &n, &size, + NULL, 0) < 0) { + warn("hw.snd.basename_clone failed"); + return (-1); + } + if (n == 0) { + warnx("warning: hw.snd.basename_clone not set. " + "/dev/dsp is managed externally and does not " + "change with the default unit change here."); + } + } if ((n = mixer_get_dunit()) < 0) { warn("cannot get default unit"); @@ -336,6 +366,43 @@ set_dunit(struct mixer *m, int dunit) } printf("default_unit: %d -> %d\n", n, dunit); + /* Hot-swap in case virtual_oss exists and is running. */ + if (vctl != NULL) { + dev = strsep(&vctl, ":"); + mode = vctl; + if (dev == NULL || mode == NULL) { + warnx("voss_device:mode tuple incomplete"); + return (-1); + } + if (strcmp(mode, "all") == 0) + opt = "-f"; + else if (strcmp(mode, "play") == 0) + opt = "-P"; + else if (strcmp(mode, "rec") == 0) + opt = "-R"; + else { + warnx("please use one of the following modes: " + "all, play, rec"); + return (-1); + } + snprintf(buf, sizeof(buf), "/dev/dsp%d", dunit); + switch (fork()) { + case -1: + warn("fork"); + break; + case 0: + rc = execl("/usr/local/sbin/virtual_oss_cmd", + "virtual_oss_cmd", dev, opt, buf, NULL); + if (rc < 0) + warn("virtual_oss_cmd"); + _exit(0); + default: + if (wait(NULL) < 0) + warn("wait"); + break; + } + } + return (0); }