From 6918eaa94e12ec1ac994a1b9b68c930ea2f91548 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Thu, 5 Sep 2019 09:05:33 +0200 Subject: [PATCH 01/10] Remove unused #include --- sndiod/listen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sndiod/listen.c b/sndiod/listen.c index 938a94f..54c9684 100644 --- a/sndiod/listen.c +++ b/sndiod/listen.c @@ -16,7 +16,6 @@ */ #include #include -#include #include #include From 0310ad45e93024cf4a72c1620e0f7eb8e251ac46 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Sep 2019 09:16:58 +0200 Subject: [PATCH 02/10] Revert "Allow switching between devices without disconnecting clients." This change was not right: First, upon SIGHUP, next device should be opened before the old one is closed. Second the migration code doesn't reinitialize the conversion layer which breaks audio when switching between devices with different channel counts. This reverts commit 5bc17e6cea0865a32c65a767e3abb6fa774fcc47. --- sndiod/dev.c | 93 ++---------------------------------------------- sndiod/dev.h | 3 +- sndiod/midi.c | 28 ++------------- sndiod/midi.h | 3 +- sndiod/miofile.c | 28 ++------------- sndiod/siofile.c | 43 +++++----------------- sndiod/sndiod.8 | 29 +-------------- sndiod/sndiod.c | 50 +++++--------------------- sndiod/utils.c | 27 -------------- sndiod/utils.h | 8 ----- 10 files changed, 26 insertions(+), 286 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 6e7b00f..ed88446 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -969,8 +969,7 @@ dev_new(char *path, struct aparams *par, return NULL; } d = xmalloc(sizeof(struct dev)); - d->path_list = NULL; - namelist_add(&d->path_list, path); + d->path = xstrdup(path); d->num = dev_sndnum++; d->opt_list = NULL; @@ -1175,94 +1174,6 @@ dev_close(struct dev *d) dev_close_do(d); } -/* - * Close the device, but attempt to migrate everything to a new sndio - * device. - */ -void -dev_reopen(struct dev *d) -{ - struct slot *s; - long long pos; - unsigned int mode, round, bufsz, rate, pstate; - int delta; - - /* not opened */ - if (d->pstate == DEV_CFG) - return; - - if (log_level >= 1) { - dev_log(d); - log_puts(": reopening device\n"); - } - - /* save state */ - mode = d->mode; - round = d->round; - bufsz = d->bufsz; - rate = d->rate; - delta = d->delta; - pstate = d->pstate; - - /* close device */ - dev_close_do(d); - - /* open device */ - if (!dev_open_do(d)) { - if (log_level >= 1) { - dev_log(d); - log_puts(": found no working alternate device\n"); - } - dev_exitall(d); - return; - } - - /* check if new parameters are compatible with old ones */ - if (d->mode != mode || - d->round != round || - d->bufsz != bufsz || - d->rate != rate) { - if (log_level >= 1) { - dev_log(d); - log_puts(": alternate device not compatible\n"); - } - dev_close(d); - return; - } - - /* - * adjust time positions, make anything go back delta ticks, so - * that the new device can start at zero - */ - for (s = d->slot_list; s != NULL; s = s->next) { - pos = (long long)(d->round - delta) * s->round + s->delta_rem; - s->delta_rem = pos % d->round; - s->delta += pos / (int)d->round; - s->delta -= s->round; - if (log_level >= 2) { - slot_log(s); - log_puts(": adjusted: delta -> "); - log_puti(s->delta); - log_puts(", delta_rem -> "); - log_puti(s->delta_rem); - log_puts("\n"); - } - } - if (d->tstate == MMC_RUN) { - d->mtc.delta -= delta * MTC_SEC; - if (log_level >= 2) { - dev_log(d); - log_puts(": adjusted mtc: delta ->"); - log_puti(d->mtc.delta); - log_puts("\n"); - } - } - - /* start the device if needed */ - if (pstate == DEV_RUN) - dev_wakeup(d); -} - int dev_ref(struct dev *d) { @@ -1369,7 +1280,7 @@ dev_del(struct dev *d) } midi_del(d->midi); *p = d->next; - namelist_clear(&d->path_list); + xfree(d->path); xfree(d); } diff --git a/sndiod/dev.h b/sndiod/dev.h index 0fff249..3719d87 100644 --- a/sndiod/dev.h +++ b/sndiod/dev.h @@ -159,7 +159,7 @@ struct dev { #define DEV_INIT 1 /* stopped */ #define DEV_RUN 2 /* playin & recording */ unsigned int pstate; /* one of above */ - struct name *path_list; + char *path; /* sio path */ /* * actual parameters and runtime state (i.e. once opened) @@ -201,7 +201,6 @@ extern struct dev *dev_list; void dev_log(struct dev *); void dev_close(struct dev *); -void dev_reopen(struct dev *); struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); struct dev *dev_bynum(int); diff --git a/sndiod/midi.c b/sndiod/midi.c index 00f941c..971794e 100644 --- a/sndiod/midi.c +++ b/sndiod/midi.c @@ -439,8 +439,7 @@ port_new(char *path, unsigned int mode, int hold) struct port *c; c = xmalloc(sizeof(struct port)); - c->path_list = NULL; - namelist_add(&c->path_list, path); + c->path = xstrdup(path); c->state = PORT_CFG; c->hold = hold; c->midi = midi_new(&port_midiops, c, mode); @@ -470,7 +469,7 @@ port_del(struct port *c) #endif } *p = c->next; - namelist_clear(&c->path_list); + xfree(c->path); xfree(c); } @@ -595,26 +594,3 @@ port_done(struct port *c) if (c->state == PORT_INIT) port_drain(c); } - -void -port_reopen(struct port *p) -{ - if (p->state == PORT_CFG) - return; - - if (log_level >= 1) { - port_log(p); - log_puts(": reopening port\n"); - } - - port_mio_close(p); - - if (!port_mio_open(p)) { - if (log_level >= 1) { - port_log(p); - log_puts(": found no working alternate port\n"); - } - p->state = PORT_CFG; - port_exitall(p); - } -} diff --git a/sndiod/midi.h b/sndiod/midi.h index 26f6e86..67a3563 100644 --- a/sndiod/midi.h +++ b/sndiod/midi.h @@ -88,7 +88,7 @@ struct port { #define PORT_DRAIN 2 unsigned int state; unsigned int num; /* port serial number */ - struct name *path_list; + char *path; int hold; /* hold the port open ? */ struct midi *midi; }; @@ -121,6 +121,5 @@ int port_init(struct port *); void port_done(struct port *); void port_drain(struct port *); int port_close(struct port *); -void port_reopen(struct port *); #endif /* !defined(MIDI_H) */ diff --git a/sndiod/miofile.c b/sndiod/miofile.c index 7669468..5b037f0 100644 --- a/sndiod/miofile.c +++ b/sndiod/miofile.c @@ -44,35 +44,13 @@ struct fileops port_mio_ops = { port_mio_hup }; -/* - * open the port using one of the provided paths - */ -static char * -port_mio_openlist(struct port *c, unsigned int mode) -{ - struct name *n; - - n = c->path_list; - while (1) { - if (n == NULL) - break; - c->mio.hdl = mio_open(n->str, mode, 1); - if (c->mio.hdl != NULL) - return n->str; - n = n->next; - } - return NULL; -} - int port_mio_open(struct port *p) { - char *path; - - path = port_mio_openlist(p, p->midi->mode); + p->mio.hdl = mio_open(p->path, p->midi->mode, 1); if (p->mio.hdl == NULL) return 0; - p->mio.file = file_new(&port_mio_ops, p, path, mio_nfds(p->mio.hdl)); + p->mio.file = file_new(&port_mio_ops, p, p->path, mio_nfds(p->mio.hdl)); return 1; } @@ -150,5 +128,5 @@ port_mio_hup(void *arg) { struct port *p = arg; - port_reopen(p); + port_close(p); } diff --git a/sndiod/siofile.c b/sndiod/siofile.c index 5757623..9f36f8a 100644 --- a/sndiod/siofile.c +++ b/sndiod/siofile.c @@ -83,26 +83,6 @@ dev_sio_timeout(void *arg) dev_close(d); } -/* - * open the device using one of the provided paths - */ -static char * -dev_sio_openlist(struct dev *d, unsigned int mode) -{ - struct name *n; - - n = d->path_list; - while (1) { - if (n == NULL) - break; - d->sio.hdl = sio_open(n->str, mode, 1); - if (d->sio.hdl != NULL) - return n->str; - n = n->next; - } - return NULL; -} - /* * open the device. */ @@ -111,18 +91,17 @@ dev_sio_open(struct dev *d) { struct sio_par par; unsigned int mode = d->mode & (MODE_PLAY | MODE_REC); - char *path; - path = dev_sio_openlist(d, mode); - if (path == NULL) { + d->sio.hdl = sio_open(d->path, mode, 1); + if (d->sio.hdl == NULL) { if (mode != (SIO_PLAY | SIO_REC)) return 0; - path = dev_sio_openlist(d, SIO_PLAY); - if (path != NULL) + d->sio.hdl = sio_open(d->path, SIO_PLAY, 1); + if (d->sio.hdl != NULL) mode = SIO_PLAY; else { - path = dev_sio_openlist(d, SIO_REC); - if (path != NULL) + d->sio.hdl = sio_open(d->path, SIO_REC, 1); + if (d->sio.hdl != NULL) mode = SIO_REC; else return 0; @@ -232,14 +211,8 @@ dev_sio_open(struct dev *d) if (!(mode & MODE_REC)) d->mode &= ~MODE_REC; sio_onmove(d->sio.hdl, dev_sio_onmove, d); - d->sio.file = file_new(&dev_sio_ops, d, path, sio_nfds(d->sio.hdl)); + d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl)); timo_set(&d->sio.watchdog, dev_sio_timeout, d); - if (log_level >= 1) { - dev_log(d); - log_puts(": using "); - log_puts(path); - log_puts("\n"); - } return 1; bad_close: sio_close(d->sio.hdl); @@ -520,5 +493,5 @@ dev_sio_hup(void *arg) log_puts(": disconnected\n"); } #endif - dev_reopen(d); + dev_close(d); } diff --git a/sndiod/sndiod.8 b/sndiod/sndiod.8 index 58b29bf..7c26b0b 100644 --- a/sndiod/sndiod.8 +++ b/sndiod/sndiod.8 @@ -29,12 +29,10 @@ .Op Fl C Ar min : Ns Ar max .Op Fl c Ar min : Ns Ar max .Op Fl e Ar enc -.Op Fl F Ar device .Op Fl f Ar device .Op Fl j Ar flag .Op Fl L Ar addr .Op Fl m Ar mode -.Op Fl Q Ar port .Op Fl q Ar port .Op Fl r Ar rate .Op Fl s Ar name @@ -184,18 +182,6 @@ or Only the signedness and the precision are mandatory. Examples: .Va u8 , s16le , s24le3 , s24le4lsb . -.It Fl F Ar device -Specify an alternate device to use. -If doesn't work, the one given with the last -.Fl f -or -.Fl F -options will be used. -For instance, specifying a USB device following a -PCI device allows -.Nm -to use the USB one preferably when it's connected -and to fall back to the PCI one when it's disconnected. .It Fl f Ar device Add this .Xr sndio 7 @@ -259,15 +245,6 @@ but the same sub-device cannot be used for both recording and monitoring. The default is .Ar play , Ns Ar rec (i.e. full-duplex). -.It Fl Q Ar port -Specify an alternate MIDI port to use. -If doesn't work, the one given with the last -.Fl Q -or -.Fl q -options will be used. -For instance, this allows to replace a USB MIDI controller without -the need to restart programs using it. .It Fl q Ar port Expose the given MIDI port. This allows multiple programs to share the port. @@ -399,15 +376,11 @@ is If .Nm is sent +.Dv SIGHUP , .Dv SIGINT or .Dv SIGTERM , it terminates. -If -.Nm -is sent -.Dv SIGHUP , -it reopens all audio devices and MIDI ports. .Pp By default, when the program cannot accept recorded data fast enough or cannot provide data to play fast enough, diff --git a/sndiod/sndiod.c b/sndiod/sndiod.c index 56cde52..5d3bd73 100644 --- a/sndiod/sndiod.c +++ b/sndiod/sndiod.c @@ -68,7 +68,7 @@ * block size if neither ``-z'' nor ``-b'' is used */ #ifndef DEFAULT_ROUND -#define DEFAULT_ROUND 480 +#define DEFAULT_ROUND 960 #endif /* @@ -86,7 +86,6 @@ #endif void sigint(int); -void sighup(int); void opt_ch(int *, int *); void opt_enc(struct aparams *); int opt_mmc(void); @@ -103,13 +102,12 @@ struct opt *mkopt(char *, struct dev *, int, int, int, int, int, int, int, int); unsigned int log_level = 0; -volatile sig_atomic_t quit_flag = 0, reopen_flag = 0; +volatile sig_atomic_t quit_flag = 0; char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] " - "[-C min:max] [-c min:max]\n\t" - "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t" - "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t" - "[-v volume] [-w flag] [-z nframes]\n"; + "[-C min:max] [-c min:max] [-e enc]\n\t" + "[-f device] [-j flag] [-L addr] [-m mode] [-q port] [-r rate]\n\t" + "[-s name] [-t mode] [-U unit] [-v volume] [-w flag] [-z nframes]\n"; /* * SIGINT handler, it raises the quit flag. If the flag is already set, @@ -124,16 +122,6 @@ sigint(int s) quit_flag = 1; } -/* - * SIGHUP handler, it raises the reopen flag, which requests devices - * to be reopened. - */ -void -sighup(int s) -{ - reopen_flag = 1; -} - void opt_ch(int *rcmin, int *rcmax) { @@ -236,7 +224,6 @@ setsig(void) struct sigaction sa; quit_flag = 0; - reopen_flag = 0; sigfillset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = sigint; @@ -244,7 +231,6 @@ setsig(void) err(1, "sigaction(int) failed"); if (sigaction(SIGTERM, &sa, NULL) == -1) err(1, "sigaction(term) failed"); - sa.sa_handler = sighup; if (sigaction(SIGHUP, &sa, NULL) == -1) err(1, "sigaction(hup) failed"); } @@ -301,8 +287,7 @@ mkdev(char *path, struct aparams *par, struct dev *d; for (d = dev_list; d != NULL; d = d->next) { - if (d->path_list->next == NULL && - strcmp(d->path_list->str, path) == 0) + if (strcmp(d->path, path) == 0) return d; } if (!bufsz && !round) { @@ -324,8 +309,7 @@ mkport(char *path, int hold) struct port *c; for (c = port_list; c != NULL; c = c->next) { - if (c->path_list->next == NULL && - strcmp(c->path_list->str, path) == 0) + if (strcmp(c->path, path) == 0) return c; } c = port_new(path, MODE_MIDIMASK, hold); @@ -391,8 +375,7 @@ main(int argc, char **argv) mode = MODE_PLAY | MODE_REC; tcpaddr_list = NULL; - while ((c = getopt(argc, argv, - "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) { + while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) { switch (c) { case 'd': log_level++; @@ -449,11 +432,6 @@ main(int argc, char **argv) case 'q': mkport(optarg, hold); break; - case 'Q': - if (port_list == NULL) - errx(1, "-Q %s: no ports defined", optarg); - namelist_add(&port_list->path_list, optarg); - break; case 'a': hold = opt_onoff(); break; @@ -474,11 +452,6 @@ main(int argc, char **argv) mkdev(optarg, &par, 0, bufsz, round, rate, hold, autovol); break; - case 'F': - if (dev_list == NULL) - errx(1, "-F %s: no devices defined", optarg); - namelist_add(&dev_list->path_list, optarg); - break; default: fputs(usagestr, stderr); return 1; @@ -546,13 +519,6 @@ main(int argc, char **argv) for (;;) { if (quit_flag) break; - if (reopen_flag) { - reopen_flag = 0; - for (d = dev_list; d != NULL; d = d->next) - dev_reopen(d); - for (p = port_list; p != NULL; p = p->next) - port_reopen(p); - } if (!file_poll()) break; } diff --git a/sndiod/utils.c b/sndiod/utils.c index bea290b..ebb9fb5 100644 --- a/sndiod/utils.c +++ b/sndiod/utils.c @@ -188,30 +188,3 @@ xstrdup(char *s) memcpy(p, s, size); return p; } - -/* - * copy and append the given string to the name list - */ -void -namelist_add(struct name **list, char *str) -{ - struct name *n; - size_t size; - - size = strlen(str) + 1; - n = xmalloc(sizeof(struct name) + size); - memcpy(n->str, str, size); - n->next = *list; - *list = n; -} - -void -namelist_clear(struct name **list) -{ - struct name *n; - - while ((n = *list) != NULL) { - *list = n->next; - xfree(n); - } -} diff --git a/sndiod/utils.h b/sndiod/utils.h index ca3e089..f11b675 100644 --- a/sndiod/utils.h +++ b/sndiod/utils.h @@ -20,11 +20,6 @@ #include -struct name { - struct name *next; - char str[]; -}; - void log_puts(char *); void log_putx(unsigned long); void log_putu(unsigned long); @@ -36,9 +31,6 @@ void *xmalloc(size_t); char *xstrdup(char *); void xfree(void *); -void namelist_add(struct name **, char *); -void namelist_clear(struct name **); - /* * Log levels: * From cf94ce9ae8b65c9162b4c6aa5f3ee554f5d64d44 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Sep 2019 09:29:32 +0200 Subject: [PATCH 03/10] Move device buffer allocation to its own routines. This makes the code more readable as device and slot buffer allocation routines are similar. No behavior change. --- sndiod/dev.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index ed88446..1105e8d 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -58,10 +58,10 @@ int dev_getpos(struct dev *); struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); void dev_adjpar(struct dev *, int, int, int); -int dev_open_do(struct dev *); +int dev_allocbufs(struct dev *); int dev_open(struct dev *); void dev_exitall(struct dev *); -void dev_close_do(struct dev *); +void dev_freebufs(struct dev *); void dev_close(struct dev *); int dev_ref(struct dev *); void dev_unref(struct dev *); @@ -1032,15 +1032,8 @@ dev_adjpar(struct dev *d, int mode, * monitor, midi control, and any necessary conversions. */ int -dev_open_do(struct dev *d) +dev_allocbufs(struct dev *d) { - if (!dev_sio_open(d)) { - if (log_level >= 1) { - dev_log(d); - log_puts(": failed to open audio device\n"); - } - return 0; - } if (d->mode & MODE_REC) { /* * Create device <-> demuxer buffer @@ -1074,7 +1067,6 @@ dev_open_do(struct dev *d) } else d->encbuf = NULL; } - d->pstate = DEV_INIT; if (log_level >= 2) { dev_log(d); log_puts(": "); @@ -1115,8 +1107,16 @@ dev_open(struct dev *d) d->pchan = 2; if (d->rchan == 0) d->rchan = 2; - if (!dev_open_do(d)) + if (!dev_sio_open(d)) { + if (log_level >= 1) { + dev_log(d); + log_puts(": failed to open audio device\n"); + } return 0; + } + if (!dev_allocbufs(d)) + return 0; + d->pstate = DEV_INIT; return 1; } @@ -1142,7 +1142,7 @@ dev_exitall(struct dev *d) * ensure buffers are drained */ void -dev_close_do(struct dev *d) +dev_freebufs(struct dev *d) { #ifdef DEBUG if (log_level >= 3) { @@ -1150,8 +1150,6 @@ dev_close_do(struct dev *d) log_puts(": closing\n"); } #endif - d->pstate = DEV_CFG; - dev_sio_close(d); if (d->mode & MODE_PLAY) { if (d->encbuf != NULL) xfree(d->encbuf); @@ -1171,7 +1169,9 @@ void dev_close(struct dev *d) { dev_exitall(d); - dev_close_do(d); + d->pstate = DEV_CFG; + dev_sio_close(d); + dev_freebufs(d); } int From 5e033425c0f8db4192abd6d744831d0e498a309d Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Sep 2019 09:34:59 +0200 Subject: [PATCH 04/10] Move slot convertions setup in its own routine. --- sndiod/dev.c | 56 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 1105e8d..668cda8 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -83,6 +83,7 @@ void slot_attach(struct slot *); void slot_ready(struct slot *); void slot_allocbufs(struct slot *); void slot_freebufs(struct slot *); +void slot_initconv(struct slot *); void slot_start(struct slot *); void slot_detach(struct slot *); void slot_stop(struct slot *); @@ -1432,15 +1433,12 @@ dev_mmcloc(struct dev *d, unsigned int origin) * allocate buffers & conversion chain */ void -slot_allocbufs(struct slot *s) +slot_initconv(struct slot *s) { unsigned int dev_nch; struct dev *d = s->dev; if (s->mode & MODE_PLAY) { - s->mix.bpf = s->par.bps * s->mix.nch; - abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf); - dev_nch = s->opt->pmax - s->opt->pmin + 1; s->mix.decbuf = NULL; s->mix.resampbuf = NULL; @@ -1459,21 +1457,14 @@ slot_allocbufs(struct slot *s) s->opt->pmin, s->opt->pmax); if (!aparams_native(&s->par)) { dec_init(&s->mix.dec, &s->par, s->mix.nch); - s->mix.decbuf = - xmalloc(s->round * s->mix.nch * sizeof(adata_t)); } if (s->rate != d->rate) { resamp_init(&s->mix.resamp, s->round, d->round, s->mix.nch); - s->mix.resampbuf = - xmalloc(d->round * s->mix.nch * sizeof(adata_t)); } } if (s->mode & MODE_RECMASK) { - s->sub.bpf = s->par.bps * s->sub.nch; - abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf); - dev_nch = s->opt->rmax - s->opt->rmin + 1; s->sub.encbuf = NULL; s->sub.resampbuf = NULL; @@ -1493,13 +1484,9 @@ slot_allocbufs(struct slot *s) if (s->rate != d->rate) { resamp_init(&s->sub.resamp, d->round, s->round, s->sub.nch); - s->sub.resampbuf = - xmalloc(d->round * s->sub.nch * sizeof(adata_t)); } if (!aparams_native(&s->par)) { enc_init(&s->sub.enc, &s->par, s->sub.nch); - s->sub.encbuf = - xmalloc(s->round * s->sub.nch * sizeof(adata_t)); } /* @@ -1519,6 +1506,45 @@ slot_allocbufs(struct slot *s) s->appbufsz * s->sub.nch * sizeof(adata_t)); } } +} + +/* + * allocate buffers & conversion chain + */ +void +slot_allocbufs(struct slot *s) +{ + struct dev *d = s->dev; + + if (s->mode & MODE_PLAY) { + s->mix.bpf = s->par.bps * s->mix.nch; + abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf); + + if (!aparams_native(&s->par)) { + s->mix.decbuf = + xmalloc(s->round * s->mix.nch * sizeof(adata_t)); + } + if (s->rate != d->rate) { + s->mix.resampbuf = + xmalloc(d->round * s->mix.nch * sizeof(adata_t)); + } + } + + if (s->mode & MODE_RECMASK) { + s->sub.bpf = s->par.bps * s->sub.nch; + abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf); + + if (s->rate != d->rate) { + s->sub.resampbuf = + xmalloc(d->round * s->sub.nch * sizeof(adata_t)); + } + if (!aparams_native(&s->par)) { + s->sub.encbuf = + xmalloc(s->round * s->sub.nch * sizeof(adata_t)); + } + } + + slot_initconv(s); #ifdef DEBUG if (log_level >= 3) { From 7cd9c4b0a9e9eb361f4011b1e6637aa339e1ebdb Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Sep 2019 09:36:33 +0200 Subject: [PATCH 05/10] Don't attempt to join/expand nonexistent channels. If the (hardware) device has fewer channels than the exposed sub-device and -jon is used, then mix the samples only to channels that exist on the device. --- sndiod/dev.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 668cda8..eb364e6 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -1435,11 +1435,13 @@ dev_mmcloc(struct dev *d, unsigned int origin) void slot_initconv(struct slot *s) { - unsigned int dev_nch; + unsigned int dev_nch, max_nch; struct dev *d = s->dev; if (s->mode & MODE_PLAY) { dev_nch = s->opt->pmax - s->opt->pmin + 1; + if (dev_nch > d->pchan) + dev_nch = d->pchan; s->mix.decbuf = NULL; s->mix.resampbuf = NULL; s->mix.join = 1; @@ -1465,7 +1467,10 @@ slot_initconv(struct slot *s) } if (s->mode & MODE_RECMASK) { + max_nch = (s->mode & MODE_MON) ? d->pchan : d->rchan; dev_nch = s->opt->rmax - s->opt->rmin + 1; + if (dev_nch > max_nch) + dev_nch = max_nch; s->sub.encbuf = NULL; s->sub.resampbuf = NULL; s->sub.join = 1; @@ -1477,8 +1482,8 @@ slot_initconv(struct slot *s) s->sub.expand = s->sub.nch / dev_nch; } cmap_init(&s->sub.cmap, - 0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1, - s->opt->rmin, s->opt->rmax, + 0, max_nch - 1, + s->opt->rmin, s->opt->rmin + dev_nch - 1, s->opt->rmin, s->opt->rmin + s->sub.nch - 1, s->opt->rmin, s->opt->rmin + s->sub.nch - 1); if (s->rate != d->rate) { From e922c66fc08806cb9afcc781ee0cea058ccff287 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Wed, 18 Sep 2019 15:56:08 +0200 Subject: [PATCH 06/10] Don't set to NULL conversion buffers when initializing the slot. Bug introduced when conversions setup moved to its own routine. --- sndiod/dev.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index eb364e6..aa397a5 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -1428,7 +1428,6 @@ dev_mmcloc(struct dev *d, unsigned int origin) dev_mmcstart(d); } - /* * allocate buffers & conversion chain */ @@ -1442,8 +1441,6 @@ slot_initconv(struct slot *s) dev_nch = s->opt->pmax - s->opt->pmin + 1; if (dev_nch > d->pchan) dev_nch = d->pchan; - s->mix.decbuf = NULL; - s->mix.resampbuf = NULL; s->mix.join = 1; s->mix.expand = 1; if (s->opt->dup) { @@ -1471,8 +1468,6 @@ slot_initconv(struct slot *s) dev_nch = s->opt->rmax - s->opt->rmin + 1; if (dev_nch > max_nch) dev_nch = max_nch; - s->sub.encbuf = NULL; - s->sub.resampbuf = NULL; s->sub.join = 1; s->sub.expand = 1; if (s->opt->dup) { @@ -1525,6 +1520,8 @@ slot_allocbufs(struct slot *s) s->mix.bpf = s->par.bps * s->mix.nch; abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf); + s->mix.decbuf = NULL; + s->mix.resampbuf = NULL; if (!aparams_native(&s->par)) { s->mix.decbuf = xmalloc(s->round * s->mix.nch * sizeof(adata_t)); @@ -1539,6 +1536,8 @@ slot_allocbufs(struct slot *s) s->sub.bpf = s->par.bps * s->sub.nch; abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf); + s->sub.encbuf = NULL; + s->sub.resampbuf = NULL; if (s->rate != d->rate) { s->sub.resampbuf = xmalloc(d->round * s->sub.nch * sizeof(adata_t)); From 3935da37f643fcc78eeca2540659de7785d79f6b Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Thu, 19 Sep 2019 09:08:29 +0200 Subject: [PATCH 07/10] Setup channel join/expand after channle mapping conversions. The channel mapping conversion calculate the number of channels actually present on the hardware. This allows to join/expand the right number of channels. --- sndiod/dev.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index aa397a5..15a751b 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -1434,21 +1434,9 @@ dev_mmcloc(struct dev *d, unsigned int origin) void slot_initconv(struct slot *s) { - unsigned int dev_nch, max_nch; struct dev *d = s->dev; if (s->mode & MODE_PLAY) { - dev_nch = s->opt->pmax - s->opt->pmin + 1; - if (dev_nch > d->pchan) - dev_nch = d->pchan; - s->mix.join = 1; - s->mix.expand = 1; - if (s->opt->dup) { - if (dev_nch > s->mix.nch) - s->mix.expand = dev_nch / s->mix.nch; - else if (dev_nch < s->mix.nch) - s->mix.join = s->mix.nch / dev_nch; - } cmap_init(&s->mix.cmap, s->opt->pmin, s->opt->pmin + s->mix.nch - 1, s->opt->pmin, s->opt->pmin + s->mix.nch - 1, @@ -1461,24 +1449,20 @@ slot_initconv(struct slot *s) resamp_init(&s->mix.resamp, s->round, d->round, s->mix.nch); } + s->mix.join = 1; + s->mix.expand = 1; + if (s->opt->dup) { + if (s->mix.cmap.nch > s->mix.nch) + s->mix.expand = s->mix.cmap.nch / s->mix.nch; + else if (s->mix.cmap.nch > 0) + s->mix.join = s->mix.nch / s->mix.cmap.nch; + } } if (s->mode & MODE_RECMASK) { - max_nch = (s->mode & MODE_MON) ? d->pchan : d->rchan; - dev_nch = s->opt->rmax - s->opt->rmin + 1; - if (dev_nch > max_nch) - dev_nch = max_nch; - s->sub.join = 1; - s->sub.expand = 1; - if (s->opt->dup) { - if (dev_nch > s->sub.nch) - s->sub.join = dev_nch / s->sub.nch; - else if (dev_nch < s->sub.nch) - s->sub.expand = s->sub.nch / dev_nch; - } cmap_init(&s->sub.cmap, - 0, max_nch - 1, - s->opt->rmin, s->opt->rmin + dev_nch - 1, + 0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1, + s->opt->rmin, s->opt->rmax, s->opt->rmin, s->opt->rmin + s->sub.nch - 1, s->opt->rmin, s->opt->rmin + s->sub.nch - 1); if (s->rate != d->rate) { @@ -1488,6 +1472,14 @@ slot_initconv(struct slot *s) if (!aparams_native(&s->par)) { enc_init(&s->sub.enc, &s->par, s->sub.nch); } + s->sub.join = 1; + s->sub.expand = 1; + if (s->opt->dup) { + if (s->sub.cmap.nch > s->sub.nch) + s->sub.join = s->sub.cmap.nch / s->sub.nch; + else if (s->sub.cmap.nch > 0) + s->sub.expand = s->sub.nch / s->sub.cmap.nch; + } /* * cmap_copy() doesn't write samples in all channels, From 441100e81228f6d983afc9b0fb85e86acab0c573 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Sat, 21 Sep 2019 06:31:41 +0200 Subject: [PATCH 08/10] Allow switching between devices without disconnecting clients, again. The new -F option allows alternate device to be specified. If the device is disconnected, the one given with the last -f or -F options will be used instead. ok mpi@ --- sndiod/dev.c | 73 +++++++++++++++++++++++++++++- sndiod/dev.h | 3 +- sndiod/midi.c | 17 ++++++- sndiod/midi.h | 3 +- sndiod/miofile.c | 62 ++++++++++++++++++++++++-- sndiod/miofile.h | 1 + sndiod/siofile.c | 112 ++++++++++++++++++++++++++++++++++++++++++++--- sndiod/siofile.h | 1 + sndiod/sndiod.8 | 29 +++++++++++- sndiod/sndiod.c | 48 +++++++++++++++++--- sndiod/utils.c | 27 ++++++++++++ sndiod/utils.h | 8 ++++ 12 files changed, 362 insertions(+), 22 deletions(-) diff --git a/sndiod/dev.c b/sndiod/dev.c index 15a751b..d31dd76 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -970,7 +970,8 @@ dev_new(char *path, struct aparams *par, return NULL; } d = xmalloc(sizeof(struct dev)); - d->path = xstrdup(path); + d->path_list = NULL; + namelist_add(&d->path_list, path); d->num = dev_sndnum++; d->opt_list = NULL; @@ -1175,6 +1176,74 @@ dev_close(struct dev *d) dev_freebufs(d); } +/* + * Close the device, but attempt to migrate everything to a new sndio + * device. + */ +int +dev_reopen(struct dev *d) +{ + struct slot *s; + long long pos; + unsigned int pstate; + int delta; + + /* not opened */ + if (d->pstate == DEV_CFG) + return 1; + + /* save state */ + delta = d->delta; + pstate = d->pstate; + + if (!dev_sio_reopen(d)) + return 0; + + /* reopen returns a stopped device */ + d->pstate = DEV_INIT; + + /* reallocate new buffers, with new parameters */ + dev_freebufs(d); + dev_allocbufs(d); + + /* + * adjust time positions, make anything go back delta ticks, so + * that the new device can start at zero + */ + for (s = d->slot_list; s != NULL; s = s->next) { + pos = (long long)s->delta * d->round + s->delta_rem; + pos -= (long long)delta * s->round; + s->delta_rem = pos % (int)d->round; + s->delta = pos / (int)d->round; + if (log_level >= 3) { + slot_log(s); + log_puts(": adjusted: delta -> "); + log_puti(s->delta); + log_puts(", delta_rem -> "); + log_puti(s->delta_rem); + log_puts("\n"); + } + + /* reinitilize the format conversion chain */ + slot_initconv(s); + } + if (d->tstate == MMC_RUN) { + d->mtc.delta -= delta * MTC_SEC; + if (log_level >= 2) { + dev_log(d); + log_puts(": adjusted mtc: delta ->"); + log_puti(d->mtc.delta); + log_puts("\n"); + } + } + + /* start the device if needed */ + if (pstate == DEV_RUN) + dev_wakeup(d); + + return 1; +} + int dev_ref(struct dev *d) { @@ -1281,7 +1350,7 @@ dev_del(struct dev *d) } midi_del(d->midi); *p = d->next; - xfree(d->path); + namelist_clear(&d->path_list); xfree(d); } diff --git a/sndiod/dev.h b/sndiod/dev.h index 3719d87..f9e8f93 100644 --- a/sndiod/dev.h +++ b/sndiod/dev.h @@ -159,7 +159,7 @@ struct dev { #define DEV_INIT 1 /* stopped */ #define DEV_RUN 2 /* playin & recording */ unsigned int pstate; /* one of above */ - char *path; /* sio path */ + struct name *path_list; /* * actual parameters and runtime state (i.e. once opened) @@ -201,6 +201,7 @@ extern struct dev *dev_list; void dev_log(struct dev *); void dev_close(struct dev *); +int dev_reopen(struct dev *); struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); struct dev *dev_bynum(int); diff --git a/sndiod/midi.c b/sndiod/midi.c index 971794e..cf7aa74 100644 --- a/sndiod/midi.c +++ b/sndiod/midi.c @@ -439,7 +439,8 @@ port_new(char *path, unsigned int mode, int hold) struct port *c; c = xmalloc(sizeof(struct port)); - c->path = xstrdup(path); + c->path_list = NULL; + namelist_add(&c->path_list, path); c->state = PORT_CFG; c->hold = hold; c->midi = midi_new(&port_midiops, c, mode); @@ -469,7 +470,7 @@ port_del(struct port *c) #endif } *p = c->next; - xfree(c->path); + namelist_clear(&c->path_list); xfree(c); } @@ -594,3 +595,15 @@ port_done(struct port *c) if (c->state == PORT_INIT) port_drain(c); } + +int +port_reopen(struct port *p) +{ + if (p->state == PORT_CFG) + return 1; + + if (!port_mio_reopen(p)) + return 0; + + return 1; +} diff --git a/sndiod/midi.h b/sndiod/midi.h index 67a3563..9d7c9f5 100644 --- a/sndiod/midi.h +++ b/sndiod/midi.h @@ -88,7 +88,7 @@ struct port { #define PORT_DRAIN 2 unsigned int state; unsigned int num; /* port serial number */ - char *path; + struct name *path_list; int hold; /* hold the port open ? */ struct midi *midi; }; @@ -121,5 +121,6 @@ int port_init(struct port *); void port_done(struct port *); void port_drain(struct port *); int port_close(struct port *); +int port_reopen(struct port *); #endif /* !defined(MIDI_H) */ diff --git a/sndiod/miofile.c b/sndiod/miofile.c index 5b037f0..1bf5e5c 100644 --- a/sndiod/miofile.c +++ b/sndiod/miofile.c @@ -44,13 +44,68 @@ struct fileops port_mio_ops = { port_mio_hup }; +/* + * open the port using one of the provided paths + */ +static struct mio_hdl * +port_mio_openlist(struct port *c, unsigned int mode) +{ + struct mio_hdl *hdl; + struct name *n; + + n = c->path_list; + while (1) { + if (n == NULL) + break; + hdl = mio_open(n->str, mode, 1); + if (hdl != NULL) { + if (log_level >= 2) { + port_log(c); + log_puts(": using "); + log_puts(n->str); + log_puts("\n"); + } + return hdl; + } + n = n->next; + } + return NULL; +} + int port_mio_open(struct port *p) { - p->mio.hdl = mio_open(p->path, p->midi->mode, 1); + p->mio.hdl = port_mio_openlist(p, p->midi->mode); if (p->mio.hdl == NULL) return 0; - p->mio.file = file_new(&port_mio_ops, p, p->path, mio_nfds(p->mio.hdl)); + p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(p->mio.hdl)); + return 1; +} + +/* + * Open an alternate port. Upon success, close the old port + * and continue using the new one. + */ +int +port_mio_reopen(struct port *p) +{ + struct mio_hdl *hdl; + + hdl = port_mio_openlist(p, p->midi->mode); + if (hdl == NULL) { + if (log_level >= 1) { + port_log(p); + log_puts(": couldn't open an alternate port\n"); + } + return 0; + } + + /* close unused device */ + file_del(p->mio.file); + mio_close(p->mio.hdl); + + p->mio.hdl = hdl; + p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(hdl)); return 1; } @@ -128,5 +183,6 @@ port_mio_hup(void *arg) { struct port *p = arg; - port_close(p); + if (!port_reopen(p)) + port_close(p); } diff --git a/sndiod/miofile.h b/sndiod/miofile.h index 78ef047..3d971ca 100644 --- a/sndiod/miofile.h +++ b/sndiod/miofile.h @@ -25,6 +25,7 @@ struct port_mio { }; int port_mio_open(struct port *); +int port_mio_reopen(struct port *); void port_mio_close(struct port *); #endif /* !defined(MIOFILE_H) */ diff --git a/sndiod/siofile.c b/sndiod/siofile.c index 9f36f8a..19cb62d 100644 --- a/sndiod/siofile.c +++ b/sndiod/siofile.c @@ -83,6 +83,34 @@ dev_sio_timeout(void *arg) dev_close(d); } +/* + * open the device using one of the provided paths + */ +static struct sio_hdl * +dev_sio_openlist(struct dev *d, unsigned int mode) +{ + struct name *n; + struct sio_hdl *hdl; + + n = d->path_list; + while (1) { + if (n == NULL) + break; + hdl = sio_open(n->str, mode, 1); + if (hdl != NULL) { + if (log_level >= 2) { + dev_log(d); + log_puts(": using "); + log_puts(n->str); + log_puts("\n"); + } + return hdl; + } + n = n->next; + } + return NULL; +} + /* * open the device. */ @@ -92,15 +120,15 @@ dev_sio_open(struct dev *d) struct sio_par par; unsigned int mode = d->mode & (MODE_PLAY | MODE_REC); - d->sio.hdl = sio_open(d->path, mode, 1); + d->sio.hdl = dev_sio_openlist(d, mode); if (d->sio.hdl == NULL) { if (mode != (SIO_PLAY | SIO_REC)) return 0; - d->sio.hdl = sio_open(d->path, SIO_PLAY, 1); + d->sio.hdl = dev_sio_openlist(d, SIO_PLAY); if (d->sio.hdl != NULL) mode = SIO_PLAY; else { - d->sio.hdl = sio_open(d->path, SIO_REC, 1); + d->sio.hdl = dev_sio_openlist(d, SIO_REC); if (d->sio.hdl != NULL) mode = SIO_REC; else @@ -211,7 +239,7 @@ dev_sio_open(struct dev *d) if (!(mode & MODE_REC)) d->mode &= ~MODE_REC; sio_onmove(d->sio.hdl, dev_sio_onmove, d); - d->sio.file = file_new(&dev_sio_ops, d, d->path, sio_nfds(d->sio.hdl)); + d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl)); timo_set(&d->sio.watchdog, dev_sio_timeout, d); return 1; bad_close: @@ -219,6 +247,79 @@ dev_sio_open(struct dev *d) return 0; } +/* + * Open an alternate device. Upon success and if the new device is + * compatible with the old one, close the old device and continue + * using the new one. The new device is not started. + */ +int +dev_sio_reopen(struct dev *d) +{ + struct sio_par par; + struct sio_hdl *hdl; + + hdl = dev_sio_openlist(d, d->mode & (MODE_PLAY | MODE_REC)); + if (hdl == NULL) { + if (log_level >= 1) { + dev_log(d); + log_puts(": couldn't open an alternate device\n"); + } + return 0; + } + + sio_initpar(&par); + par.bits = d->par.bits; + par.bps = d->par.bps; + par.sig = d->par.sig; + par.le = d->par.le; + par.msb = d->par.msb; + if (d->mode & SIO_PLAY) + par.pchan = d->pchan; + if (d->mode & SIO_REC) + par.rchan = d->rchan; + par.appbufsz = d->bufsz; + par.round = d->round; + par.rate = d->rate; + if (!sio_setpar(hdl, &par)) + goto bad_close; + if (!sio_getpar(hdl, &par)) + goto bad_close; + + /* check if new parameters are compatible with old ones */ + if (par.round != d->round || par.bufsz != d->bufsz || + par.rate != d->rate) { + if (log_level >= 1) { + dev_log(d); + log_puts(": alternate device not compatible\n"); + } + goto bad_close; + } + + /* close unused device */ + timo_del(&d->sio.watchdog); + file_del(d->sio.file); + sio_close(d->sio.hdl); + + /* update parameters */ + d->par.bits = par.bits; + d->par.bps = par.bps; + d->par.sig = par.sig; + d->par.le = par.le; + d->par.msb = par.msb; + if (d->mode & SIO_PLAY) + d->pchan = par.pchan; + if (d->mode & SIO_REC) + d->rchan = par.rchan; + + d->sio.hdl = hdl; + d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(hdl)); + sio_onmove(hdl, dev_sio_onmove, d); + return 1; +bad_close: + sio_close(hdl); + return 0; +} + void dev_sio_close(struct dev *d) { @@ -493,5 +594,6 @@ dev_sio_hup(void *arg) log_puts(": disconnected\n"); } #endif - dev_close(d); + if (!dev_reopen(d)) + dev_close(d); } diff --git a/sndiod/siofile.h b/sndiod/siofile.h index d20066f..69c2bb4 100644 --- a/sndiod/siofile.h +++ b/sndiod/siofile.h @@ -38,6 +38,7 @@ struct dev_sio { }; int dev_sio_open(struct dev *); +int dev_sio_reopen(struct dev *); void dev_sio_close(struct dev *); void dev_sio_log(struct dev *); void dev_sio_start(struct dev *); diff --git a/sndiod/sndiod.8 b/sndiod/sndiod.8 index 7c26b0b..58b29bf 100644 --- a/sndiod/sndiod.8 +++ b/sndiod/sndiod.8 @@ -29,10 +29,12 @@ .Op Fl C Ar min : Ns Ar max .Op Fl c Ar min : Ns Ar max .Op Fl e Ar enc +.Op Fl F Ar device .Op Fl f Ar device .Op Fl j Ar flag .Op Fl L Ar addr .Op Fl m Ar mode +.Op Fl Q Ar port .Op Fl q Ar port .Op Fl r Ar rate .Op Fl s Ar name @@ -182,6 +184,18 @@ or Only the signedness and the precision are mandatory. Examples: .Va u8 , s16le , s24le3 , s24le4lsb . +.It Fl F Ar device +Specify an alternate device to use. +If doesn't work, the one given with the last +.Fl f +or +.Fl F +options will be used. +For instance, specifying a USB device following a +PCI device allows +.Nm +to use the USB one preferably when it's connected +and to fall back to the PCI one when it's disconnected. .It Fl f Ar device Add this .Xr sndio 7 @@ -245,6 +259,15 @@ but the same sub-device cannot be used for both recording and monitoring. The default is .Ar play , Ns Ar rec (i.e. full-duplex). +.It Fl Q Ar port +Specify an alternate MIDI port to use. +If doesn't work, the one given with the last +.Fl Q +or +.Fl q +options will be used. +For instance, this allows to replace a USB MIDI controller without +the need to restart programs using it. .It Fl q Ar port Expose the given MIDI port. This allows multiple programs to share the port. @@ -376,11 +399,15 @@ is If .Nm is sent -.Dv SIGHUP , .Dv SIGINT or .Dv SIGTERM , it terminates. +If +.Nm +is sent +.Dv SIGHUP , +it reopens all audio devices and MIDI ports. .Pp By default, when the program cannot accept recorded data fast enough or cannot provide data to play fast enough, diff --git a/sndiod/sndiod.c b/sndiod/sndiod.c index 5d3bd73..fe08d2b 100644 --- a/sndiod/sndiod.c +++ b/sndiod/sndiod.c @@ -86,6 +86,7 @@ #endif void sigint(int); +void sighup(int); void opt_ch(int *, int *); void opt_enc(struct aparams *); int opt_mmc(void); @@ -102,12 +103,13 @@ struct opt *mkopt(char *, struct dev *, int, int, int, int, int, int, int, int); unsigned int log_level = 0; -volatile sig_atomic_t quit_flag = 0; +volatile sig_atomic_t quit_flag = 0, reopen_flag = 0; char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] " - "[-C min:max] [-c min:max] [-e enc]\n\t" - "[-f device] [-j flag] [-L addr] [-m mode] [-q port] [-r rate]\n\t" - "[-s name] [-t mode] [-U unit] [-v volume] [-w flag] [-z nframes]\n"; + "[-C min:max] [-c min:max]\n\t" + "[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t" + "[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t" + "[-v volume] [-w flag] [-z nframes]\n"; /* * SIGINT handler, it raises the quit flag. If the flag is already set, @@ -122,6 +124,16 @@ sigint(int s) quit_flag = 1; } +/* + * SIGHUP handler, it raises the reopen flag, which requests devices + * to be reopened. + */ +void +sighup(int s) +{ + reopen_flag = 1; +} + void opt_ch(int *rcmin, int *rcmax) { @@ -224,6 +236,7 @@ setsig(void) struct sigaction sa; quit_flag = 0; + reopen_flag = 0; sigfillset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sa.sa_handler = sigint; @@ -231,6 +244,7 @@ setsig(void) err(1, "sigaction(int) failed"); if (sigaction(SIGTERM, &sa, NULL) == -1) err(1, "sigaction(term) failed"); + sa.sa_handler = sighup; if (sigaction(SIGHUP, &sa, NULL) == -1) err(1, "sigaction(hup) failed"); } @@ -287,7 +301,8 @@ mkdev(char *path, struct aparams *par, struct dev *d; for (d = dev_list; d != NULL; d = d->next) { - if (strcmp(d->path, path) == 0) + if (d->path_list->next == NULL && + strcmp(d->path_list->str, path) == 0) return d; } if (!bufsz && !round) { @@ -309,7 +324,8 @@ mkport(char *path, int hold) struct port *c; for (c = port_list; c != NULL; c = c->next) { - if (strcmp(c->path, path) == 0) + if (c->path_list->next == NULL && + strcmp(c->path_list->str, path) == 0) return c; } c = port_new(path, MODE_MIDIMASK, hold); @@ -375,7 +391,8 @@ main(int argc, char **argv) mode = MODE_PLAY | MODE_REC; tcpaddr_list = NULL; - while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) { + while ((c = getopt(argc, argv, + "a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) { switch (c) { case 'd': log_level++; @@ -432,6 +449,11 @@ main(int argc, char **argv) case 'q': mkport(optarg, hold); break; + case 'Q': + if (port_list == NULL) + errx(1, "-Q %s: no ports defined", optarg); + namelist_add(&port_list->path_list, optarg); + break; case 'a': hold = opt_onoff(); break; @@ -452,6 +474,11 @@ main(int argc, char **argv) mkdev(optarg, &par, 0, bufsz, round, rate, hold, autovol); break; + case 'F': + if (dev_list == NULL) + errx(1, "-F %s: no devices defined", optarg); + namelist_add(&dev_list->path_list, optarg); + break; default: fputs(usagestr, stderr); return 1; @@ -519,6 +546,13 @@ main(int argc, char **argv) for (;;) { if (quit_flag) break; + if (reopen_flag) { + reopen_flag = 0; + for (d = dev_list; d != NULL; d = d->next) + dev_reopen(d); + for (p = port_list; p != NULL; p = p->next) + port_reopen(p); + } if (!file_poll()) break; } diff --git a/sndiod/utils.c b/sndiod/utils.c index ebb9fb5..bea290b 100644 --- a/sndiod/utils.c +++ b/sndiod/utils.c @@ -188,3 +188,30 @@ xstrdup(char *s) memcpy(p, s, size); return p; } + +/* + * copy and append the given string to the name list + */ +void +namelist_add(struct name **list, char *str) +{ + struct name *n; + size_t size; + + size = strlen(str) + 1; + n = xmalloc(sizeof(struct name) + size); + memcpy(n->str, str, size); + n->next = *list; + *list = n; +} + +void +namelist_clear(struct name **list) +{ + struct name *n; + + while ((n = *list) != NULL) { + *list = n->next; + xfree(n); + } +} diff --git a/sndiod/utils.h b/sndiod/utils.h index f11b675..ca3e089 100644 --- a/sndiod/utils.h +++ b/sndiod/utils.h @@ -20,6 +20,11 @@ #include +struct name { + struct name *next; + char str[]; +}; + void log_puts(char *); void log_putx(unsigned long); void log_putu(unsigned long); @@ -31,6 +36,9 @@ void *xmalloc(size_t); char *xstrdup(char *); void xfree(void *); +void namelist_add(struct name **, char *); +void namelist_clear(struct name **); + /* * Log levels: * From 9ba816d28e47b125175854d0c9274e18faac1bf4 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Sat, 21 Sep 2019 06:54:59 +0200 Subject: [PATCH 09/10] Lower the default audio block size from 20ms to 10ms. The new default block size is supported by virtually all devices which allows switching between devices without further configuration. The buffer size remains the same, so this change won't affect audio stability. ok mpi@ --- sndiod/sndiod.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sndiod/sndiod.c b/sndiod/sndiod.c index fe08d2b..56cde52 100644 --- a/sndiod/sndiod.c +++ b/sndiod/sndiod.c @@ -68,7 +68,7 @@ * block size if neither ``-z'' nor ``-b'' is used */ #ifndef DEFAULT_ROUND -#define DEFAULT_ROUND 960 +#define DEFAULT_ROUND 480 #endif /* From a9ee8951fd339e995a3c4c0c147202e0e41b7b00 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Sat, 21 Sep 2019 07:04:01 +0200 Subject: [PATCH 10/10] Fix missing word in -F and -Q descriptions. --- sndiod/sndiod.8 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sndiod/sndiod.8 b/sndiod/sndiod.8 index 58b29bf..a52980b 100644 --- a/sndiod/sndiod.8 +++ b/sndiod/sndiod.8 @@ -186,7 +186,7 @@ Examples: .Va u8 , s16le , s24le3 , s24le4lsb . .It Fl F Ar device Specify an alternate device to use. -If doesn't work, the one given with the last +If it doesn't work, the one given with the last .Fl f or .Fl F @@ -261,7 +261,7 @@ The default is (i.e. full-duplex). .It Fl Q Ar port Specify an alternate MIDI port to use. -If doesn't work, the one given with the last +If it doesn't work, the one given with the last .Fl Q or .Fl q