version 1.97, 2010/06/29 06:48:39 |
version 1.98, 2010/07/06 01:12:45 |
|
|
int autostart, legacy; |
int autostart, legacy; |
struct dev *d, *dnext; |
struct dev *d, *dnext; |
unsigned active; |
unsigned active; |
|
unsigned nsock, nfile; |
|
|
/* |
/* |
* global options defaults |
* global options defaults |
|
|
legacy = 1; |
legacy = 1; |
legacy_path = NULL; |
legacy_path = NULL; |
SLIST_INIT(&cfdevs); |
SLIST_INIT(&cfdevs); |
|
nfile = nsock = 0; |
|
|
/* |
/* |
* default stream params |
* default stream params |
|
|
case 'i': |
case 'i': |
legacy = 0; |
legacy = 0; |
cfstr_add(&cd->ins, cs, optarg); |
cfstr_add(&cd->ins, cs, optarg); |
|
nfile++; |
break; |
break; |
case 'o': |
case 'o': |
legacy = 0; |
legacy = 0; |
cfstr_add(&cd->outs, cs, optarg); |
cfstr_add(&cd->outs, cs, optarg); |
|
nfile++; |
break; |
break; |
case 's': |
case 's': |
legacy = 0; |
legacy = 0; |
cfstr_add(&cd->opts, cs, optarg); |
cfstr_add(&cd->opts, cs, optarg); |
|
nsock++; |
break; |
break; |
case 'a': |
case 'a': |
legacy = 0; |
legacy = 0; |
|
|
case 'f': |
case 'f': |
legacy = 0; |
legacy = 0; |
legacy_path = optarg; |
legacy_path = optarg; |
|
if (SLIST_EMPTY(&cd->opts) && |
|
SLIST_EMPTY(&cd->ins) && |
|
SLIST_EMPTY(&cd->outs)) { |
|
cfstr_add(&cd->opts, cs, DEFAULT_OPT); |
|
nsock++; |
|
} |
cfdev_add(&cfdevs, cd, optarg); |
cfdev_add(&cfdevs, cd, optarg); |
break; |
break; |
case 'l': |
case 'l': |
|
|
exit(0); |
exit(0); |
} |
} |
|
|
if (!l_flag && unit >= 0) |
/* |
errx(1, "can't use -U without -l"); |
* Check constraints specific to -n option |
|
*/ |
if (n_flag) { |
if (n_flag) { |
if (!SLIST_EMPTY(&cfdevs) || l_flag || |
if (!SLIST_EMPTY(&cfdevs) || |
!SLIST_EMPTY(&cd->opts) || !SLIST_EMPTY(&cd->mids)) |
!SLIST_EMPTY(&cd->mids) || |
errx(1, "can't use -n with -l, -f, -q or -s"); |
!SLIST_EMPTY(&cd->opts)) |
|
errx(1, "-f, -s, and -q not allowed in loopback mode"); |
if (SLIST_EMPTY(&cd->ins) || SLIST_EMPTY(&cd->outs)) |
if (SLIST_EMPTY(&cd->ins) || SLIST_EMPTY(&cd->outs)) |
errx(1, "both -i and -o are required with -n"); |
errx(1, "-i and -o are required in loopback mode"); |
} |
} |
|
|
/* |
/* |
* if no device is given, add the default one |
* If there's no device specified, do as if the default |
|
* device is specified as last argument. |
*/ |
*/ |
if (SLIST_EMPTY(&cfdevs)) { |
if (SLIST_EMPTY(&cfdevs)) { |
|
if (SLIST_EMPTY(&cd->opts) && |
|
SLIST_EMPTY(&cd->ins) && |
|
SLIST_EMPTY(&cd->outs)) { |
|
cfstr_add(&cd->opts, cs, DEFAULT_OPT); |
|
nsock++; |
|
} |
if (!cd->hold) |
if (!cd->hold) |
errx(1, "-a not compatible with default device"); |
errx(1, "-a off not compatible with default device"); |
cfdev_add(&cfdevs, cd, "default"); |
cfdev_add(&cfdevs, cd, "default"); |
} |
} |
|
if ((cs = SLIST_FIRST(&cd->opts)) || |
|
(cs = SLIST_FIRST(&cd->ins)) || |
|
(cs = SLIST_FIRST(&cd->outs))) |
|
errx(1, "%s: no device to attach the stream to", cs->path); |
|
|
/* |
/* |
* If there are no sockets paths provided use the default. |
|
*/ |
|
if (l_flag) { |
|
SLIST_FOREACH(cd, &cfdevs, entry) { |
|
if (!SLIST_EMPTY(&cd->opts)) |
|
continue; |
|
cfstr_add(&cd->opts, cs, DEFAULT_OPT); |
|
break; |
|
} |
|
} |
|
|
|
/* |
|
* Check modes and calculate "best" device parameters. Iterate over all |
* Check modes and calculate "best" device parameters. Iterate over all |
* inputs and outputs and find the maximum sample rate and channel |
* inputs and outputs and find the maximum sample rate and channel |
* number. |
* number. |
|
|
aparams_grow(&cd->ipar, &cs->opar); |
aparams_grow(&cd->ipar, &cs->opar); |
} |
} |
} |
} |
if (l_flag && SLIST_EMPTY(&cd->opts)) |
|
errx(1, "%s: no subdevs for this device", cd->path); |
|
if (!l_flag && SLIST_EMPTY(&cd->ins) && SLIST_EMPTY(&cd->outs)) |
|
errx(1, "%s: no files for this device", cd->path); |
|
if (n_flag && (mode & MODE_MON)) |
|
errx(1, "monitoring not allowed in loopback mode"); |
|
if ((mode & MODE_MON) && !(mode & MODE_PLAY)) |
if ((mode & MODE_MON) && !(mode & MODE_PLAY)) |
errx(1, "no playback stream to monitor"); |
errx(1, "no playback stream to monitor"); |
|
if (n_flag && (mode & MODE_MON)) |
|
errx(1, "-m mon not allowed in loopback mode"); |
rate = (mode & MODE_REC) ? cd->ipar.rate : cd->opar.rate; |
rate = (mode & MODE_REC) ? cd->ipar.rate : cd->opar.rate; |
if (!cd->round) |
if (!cd->round) |
cd->round = rate / 15; |
cd->round = rate / 15; |
|
|
cd->bufsz = rate / 15 * 4; |
cd->bufsz = rate / 15 * 4; |
cd->mode = mode; |
cd->mode = mode; |
} |
} |
|
if (nsock > 0) { |
if (l_flag) { |
|
getbasepath(base, sizeof(base)); |
getbasepath(base, sizeof(base)); |
if (unit < 0) |
if (unit < 0) |
unit = 0; |
unit = 0; |
|
|
ctl_start(d->midi); |
ctl_start(d->midi); |
} |
} |
} |
} |
if (l_flag) { |
if (nsock > 0) { |
snprintf(path, sizeof(path), "%s/%s%u", base, |
snprintf(path, sizeof(path), "%s/%s%u", base, |
DEFAULT_SOFTAUDIO, unit); |
DEFAULT_SOFTAUDIO, unit); |
listen = listen_new(&listen_ops, path); |
listen = listen_new(&listen_ops, path); |
if (listen == 0) |
if (listen == NULL) |
exit(1); |
exit(1); |
if (geteuid() == 0) |
} |
privdrop(); |
if (geteuid() == 0) |
if (!d_flag && daemon(0, 0) < 0) |
privdrop(); |
|
if (l_flag) { |
|
debug_level = 0; |
|
dbg_flush(); |
|
if (daemon(0, 0) < 0) |
err(1, "daemon"); |
err(1, "daemon"); |
} |
} |
|
|
|
|
} |
} |
if (dev_list == NULL) |
if (dev_list == NULL) |
break; |
break; |
if (!l_flag && !active) |
if (nsock == 0 && !active) |
break; |
break; |
if (!file_poll()) |
if (!file_poll()) |
break; |
break; |
} |
} |
fatal: |
fatal: |
if (l_flag) |
if (nsock > 0) |
file_close(&listen->file); |
file_close(&listen->file); |
/* |
/* |
* give a chance to drain |
* give a chance to drain |
|
|
while (dev_list) |
while (dev_list) |
dev_del(dev_list); |
dev_del(dev_list); |
filelist_done(); |
filelist_done(); |
if (l_flag) { |
if (nsock > 0) { |
if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) |
if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) |
warn("rmdir(\"%s\")", base); |
warn("rmdir(\"%s\")", base); |
} |
} |
|
|
int |
int |
midicat_main(int argc, char **argv) |
midicat_main(int argc, char **argv) |
{ |
{ |
struct cfmidlist mids, ins, outs; |
struct cfdevlist cfdevs; |
struct cfmid *cm; |
struct cfmid *cm; |
|
struct cfstr *cs; |
|
struct cfdev *cd; |
struct listen *listen = NULL; |
struct listen *listen = NULL; |
int c, d_flag, l_flag, unit, fd; |
int c, d_flag, l_flag, unit, fd; |
char base[PATH_MAX], path[PATH_MAX]; |
char base[PATH_MAX], path[PATH_MAX]; |
|
|
struct aproc *p; |
struct aproc *p; |
struct abuf *buf; |
struct abuf *buf; |
const char *str; |
const char *str; |
struct dev *d; |
struct dev *d, *dnext; |
|
unsigned nsock; |
|
|
/* |
/* |
* global options defaults |
* global options defaults |
|
|
unit = -1; |
unit = -1; |
d_flag = 0; |
d_flag = 0; |
l_flag = 0; |
l_flag = 0; |
SLIST_INIT(&mids); |
SLIST_INIT(&cfdevs); |
SLIST_INIT(&ins); |
nsock = 0; |
SLIST_INIT(&outs); |
|
|
/* |
|
* default stream params |
|
*/ |
|
cs = malloc(sizeof(struct cfstr)); |
|
if (cs == NULL) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
|
cs->hdr = HDR_RAW; |
|
|
while ((c = getopt(argc, argv, "di:o:lf:q:U:")) != -1) { |
/* |
|
* default device |
|
*/ |
|
cd = malloc(sizeof(struct cfdev)); |
|
if (cd == NULL) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
|
SLIST_INIT(&cd->ins); |
|
SLIST_INIT(&cd->outs); |
|
SLIST_INIT(&cd->opts); |
|
SLIST_INIT(&cd->mids); |
|
cd->path = NULL; |
|
|
|
|
|
while ((c = getopt(argc, argv, "di:o:ls:q:U:")) != -1) { |
switch (c) { |
switch (c) { |
case 'd': |
case 'd': |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
d_flag = 1; |
d_flag = 1; |
break; |
break; |
case 'i': |
case 'i': |
cfmid_add(&ins, optarg); |
cfstr_add(&cd->ins, cs, optarg); |
break; |
break; |
case 'o': |
case 'o': |
cfmid_add(&outs, optarg); |
cfstr_add(&cd->outs, cs, optarg); |
break; |
break; |
/* XXX: backward compat, remove this */ |
|
case 'f': |
|
case 'q': |
case 'q': |
cfmid_add(&mids, optarg); |
cfmid_add(&cd->mids, optarg); |
break; |
break; |
|
case 's': |
|
cfstr_add(&cd->opts, cs, optarg); |
|
cfdev_add(&cfdevs, cd, optarg); |
|
nsock++; |
|
break; |
case 'l': |
case 'l': |
l_flag = 1; |
l_flag = 1; |
break; |
break; |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
if (argc > 0 || (SLIST_EMPTY(&ins) && SLIST_EMPTY(&outs) && !l_flag)) { |
#ifdef DEBUG |
|
if (debug_level == 0) |
|
debug_level = 1; |
|
#endif |
|
if (argc > 0) { |
midicat_usage(); |
midicat_usage(); |
exit(1); |
exit(1); |
} |
} |
if (!l_flag && unit >= 0) |
|
errx(1, "can't use -U without -l"); |
/* |
if (l_flag) { |
* If there's no device specified (-s), then create one with |
if (!SLIST_EMPTY(&ins) || !SLIST_EMPTY(&outs)) |
* reasonable defaults: |
errx(1, "can't use -i or -o with -l"); |
* |
|
* - if there are no streams (-ioq) defined, assume server mode |
|
* and expose the "defaut" option |
|
* |
|
* - if there are files (-io) but no ports (-q) to send/receive |
|
* from, add the default sndio(7) MIDI port |
|
*/ |
|
if (SLIST_EMPTY(&cfdevs)) { |
|
if (SLIST_EMPTY(&cd->mids)) { |
|
if (SLIST_EMPTY(&cd->ins) && SLIST_EMPTY(&cd->outs)) |
|
cfmid_add(&cd->mids, "default"); |
|
else { |
|
cfstr_add(&cd->opts, cs, DEFAULT_OPT); |
|
nsock++; |
|
} |
|
} |
|
cfdev_add(&cfdevs, cd, "default"); |
|
} |
|
if (nsock > 0) { |
getbasepath(base, sizeof(path)); |
getbasepath(base, sizeof(path)); |
if (unit < 0) |
if (unit < 0) |
unit = 0; |
unit = 0; |
|
|
setsig(); |
setsig(); |
filelist_init(); |
filelist_init(); |
|
|
d = dev_new_thru(); |
while (!SLIST_EMPTY(&cfdevs)) { |
if (!dev_ref(d)) |
cd = SLIST_FIRST(&cfdevs); |
errx(1, "couldn't open midi thru box"); |
SLIST_REMOVE_HEAD(&cfdevs, entry); |
if (!l_flag && APROC_OK(d->midi)) |
|
d->midi->flags |= APROC_QUIT; |
d = dev_new_thru(); |
if ((!SLIST_EMPTY(&ins) || !SLIST_EMPTY(&outs)) && SLIST_EMPTY(&mids)) { |
if (d == NULL) |
cfmid_add(&mids, "default"); |
errx(1, "%s: can't open device", cd->path); |
} |
if (!dev_ref(d)) |
while (!SLIST_EMPTY(&mids)) { |
errx(1, "couldn't open midi thru box"); |
cm = SLIST_FIRST(&mids); |
if (!SLIST_EMPTY(&cd->opts) && APROC_OK(d->midi)) |
SLIST_REMOVE_HEAD(&mids, entry); |
d->midi->flags |= APROC_QUIT; |
if (!dev_thruadd(d, cm->path, |
|
!SLIST_EMPTY(&outs) || l_flag, |
/* |
!SLIST_EMPTY(&ins) || l_flag)) { |
* register midi ports |
errx(1, "%s: can't open device", cm->path); |
*/ |
|
while (!SLIST_EMPTY(&cd->mids)) { |
|
cm = SLIST_FIRST(&cd->mids); |
|
SLIST_REMOVE_HEAD(&cd->mids, entry); |
|
if (!dev_thruadd(d, cm->path, 1, 1)) |
|
errx(1, "%s: can't open device", cm->path); |
|
free(cm); |
} |
} |
free(cm); |
|
|
/* |
|
* register files |
|
*/ |
|
while (!SLIST_EMPTY(&cd->ins)) { |
|
cs = SLIST_FIRST(&cd->ins); |
|
SLIST_REMOVE_HEAD(&cd->ins, entry); |
|
if (strcmp(cs->path, "-") == 0) { |
|
fd = STDIN_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
warn("stdin"); |
|
} else { |
|
fd = open(cs->path, O_RDONLY | O_NONBLOCK, 0666); |
|
if (fd < 0) |
|
err(1, "%s", cs->path); |
|
} |
|
stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path); |
|
p = rfile_new(stdx); |
|
buf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setout(p, buf); |
|
dev_midiattach(d, buf, NULL); |
|
free(cs); |
|
} |
|
while (!SLIST_EMPTY(&cd->outs)) { |
|
cs = SLIST_FIRST(&cd->outs); |
|
SLIST_REMOVE_HEAD(&cd->outs, entry); |
|
if (strcmp(cs->path, "-") == 0) { |
|
fd = STDOUT_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
warn("stdout"); |
|
} else { |
|
fd = open(cs->path, |
|
O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666); |
|
if (fd < 0) |
|
err(1, "%s", cs->path); |
|
} |
|
stdx = (struct file *)pipe_new(&pipe_ops, fd, cs->path); |
|
p = wfile_new(stdx); |
|
buf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setin(p, buf); |
|
dev_midiattach(d, NULL, buf); |
|
free(cs); |
|
} |
|
while (!SLIST_EMPTY(&cd->opts)) { |
|
cs = SLIST_FIRST(&cd->opts); |
|
SLIST_REMOVE_HEAD(&cd->opts, entry); |
|
opt_new(cs->path, d, NULL, NULL, 0, 0, 0, 0); |
|
free(cs); |
|
} |
|
free(cd); |
} |
} |
if (l_flag) { |
if (nsock > 0) { |
opt_new(DEFAULT_OPT, d, NULL, NULL, 0, 0, 0, 0); |
|
snprintf(path, sizeof(path), "%s/%s%u", base, |
snprintf(path, sizeof(path), "%s/%s%u", base, |
DEFAULT_MIDITHRU, unit); |
DEFAULT_MIDITHRU, unit); |
listen = listen_new(&listen_ops, path); |
listen = listen_new(&listen_ops, path); |
if (geteuid() == 0) |
if (listen == NULL) |
privdrop(); |
exit(1); |
if (!d_flag && daemon(0, 0) < 0) |
} |
|
if (geteuid() == 0) |
|
privdrop(); |
|
if (l_flag) { |
|
debug_level = 0; |
|
dbg_flush(); |
|
if (daemon(0, 0) < 0) |
err(1, "daemon"); |
err(1, "daemon"); |
} |
} |
while (!SLIST_EMPTY(&ins)) { |
|
cm = SLIST_FIRST(&ins); |
|
SLIST_REMOVE_HEAD(&ins, entry); |
|
if (strcmp(cm->path, "-") == 0) { |
|
fd = STDIN_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
warn("stdin"); |
|
} else { |
|
fd = open(cm->path, O_RDONLY | O_NONBLOCK, 0666); |
|
if (fd < 0) |
|
err(1, "%s", cm->path); |
|
} |
|
stdx = (struct file *)pipe_new(&pipe_ops, fd, cm->path); |
|
p = rfile_new(stdx); |
|
buf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setout(p, buf); |
|
dev_midiattach(d, buf, NULL); |
|
free(cm); |
|
} |
|
while (!SLIST_EMPTY(&outs)) { |
|
cm = SLIST_FIRST(&outs); |
|
SLIST_REMOVE_HEAD(&outs, entry); |
|
if (strcmp(cm->path, "-") == 0) { |
|
fd = STDOUT_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
warn("stdout"); |
|
} else { |
|
fd = open(cm->path, |
|
O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666); |
|
if (fd < 0) |
|
err(1, "%s", cm->path); |
|
} |
|
stdx = (struct file *)pipe_new(&pipe_ops, fd, cm->path); |
|
p = wfile_new(stdx); |
|
buf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setin(p, buf); |
|
dev_midiattach(d, NULL, buf); |
|
free(cm); |
|
} |
|
/* |
/* |
* loop, start processing |
* loop, start processing |
*/ |
*/ |
for (;;) { |
for (;;) { |
if (quit_flag) |
if (quit_flag) |
break; |
break; |
if (!dev_run(d)) |
for (d = dev_list; d != NULL; d = dnext) { |
break; |
dnext = d->next; |
|
if (!dev_run(d)) |
|
goto fatal; |
|
} |
if (!file_poll()) |
if (!file_poll()) |
break; |
break; |
} |
} |
if (l_flag) |
fatal: |
|
if (nsock > 0) |
file_close(&listen->file); |
file_close(&listen->file); |
dev_unref(d); |
|
dev_del(d); |
|
/* |
/* |
* drain |
* give a chance to drain |
*/ |
*/ |
|
for (d = dev_list; d != NULL; d = d->next) |
|
dev_drain(d); |
while (file_poll()) |
while (file_poll()) |
; /* nothing */ |
; /* nothing */ |
|
|
|
while (dev_list) |
|
dev_del(dev_list); |
filelist_done(); |
filelist_done(); |
if (l_flag) { |
if (nsock > 0) { |
if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) |
if (rmdir(base) < 0 && errno != ENOTEMPTY && errno != EPERM) |
warn("rmdir(\"%s\")", base); |
warn("rmdir(\"%s\")", base); |
} |
} |