From 21b94bc27644f2add3677fb15d2f4c9e72d76f74 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 1 Dec 2005 11:32:28 +0000 Subject: [PATCH] amixer - Add -s option - Add -s option to read from stdin the command sequentially. - Suppress unneeded warnings in sset. --- amixer/amixer.1 | 15 +++- amixer/amixer.c | 233 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 172 insertions(+), 76 deletions(-) diff --git a/amixer/amixer.1 b/amixer/amixer.1 index 2f24183..e8fc63b 100644 --- a/amixer/amixer.1 +++ b/amixer/amixer.1 @@ -2,7 +2,7 @@ .SH NAME amixer \- command-line mixer for ALSA soundcard driver .SH SYNOPSIS -\fBamixer\fP [\fI\-c\fP card] [\fIcmd\fP] +\fBamixer\fP [\fI\-option\fP] [\fIcmd\fP] .SH DESCRIPTION \fBamixer\fP allows command-line control of the mixer for the ALSA soundcard driver. @@ -73,16 +73,25 @@ the \fIcset\fP command. .SH OPTIONS .TP -[\fI\-c\fP card] +\fI\-c\fP card Select the card number to control. The device name created from this parameter has syntax 'hw:N' where N is specified card number. .TP -[\fI\-D\fP device] +\fI\-D\fP device Select the device name to control. The default control name is 'default'. +.TP +\fI\-s\fP | \fI\-\-stdin\fP + +Read from stdin and execute the command on each line sequentially. +When this option is given, the command in command-line arguments is ignored. + +Only sset and cset are accepted. Other commands are ignored. +The commands to unmatched ids are ignored without errors too. + .TP \fI\-h\fP Help: show syntax. diff --git a/amixer/amixer.c b/amixer/amixer.c index 2cf7647..39f9582 100644 --- a/amixer/amixer.c +++ b/amixer/amixer.c @@ -31,26 +31,17 @@ #include #include "amixer.h" -#define HELPID_HELP 1000 -#define HELPID_CARD 1001 -#define HELPID_DEVICE 1002 -#define HELPID_QUIET 1003 -#define HELPID_INACTIVE 1004 -#define HELPID_DEBUG 1005 -#define HELPID_VERSION 1006 -#define HELPID_NOCHECK 1007 -#define HELPID_ABSTRACT 1008 - #define LEVEL_BASIC (1<<0) #define LEVEL_INACTIVE (1<<1) #define LEVEL_ID (1<<2) -int quiet = 0; -int debugflag = 0; -int no_check = 0; -int smixer_level = 0; -struct snd_mixer_selem_regopt smixer_options; -char card[64] = "default"; +static int quiet = 0; +static int debugflag = 0; +static int no_check = 0; +static int smixer_level = 0; +static int ignore_error = 0; +static struct snd_mixer_selem_regopt smixer_options; +static char card[64] = "default"; static void error(const char *fmt,...) { @@ -65,7 +56,7 @@ static void error(const char *fmt,...) static int help(void) { - printf("Usage: amixer command\n"); + printf("Usage: amixer [command]\n"); printf("\nAvailable options:\n"); printf(" -h,--help this help\n"); printf(" -c,--card N select the card\n"); @@ -76,6 +67,7 @@ static int help(void) printf(" -q,--quiet be quiet\n"); printf(" -i,--inactive show also inactive controls\n"); printf(" -a,--abstract L select abstraction level (none or basic)\n"); + printf(" -s,--stdin Read and execute commands from stdin sequentially\n"); printf("\nAvailable commands:\n"); printf(" scontrols show all mixer simple controls\n"); printf(" scontents show contents of all mixer simple controls (default command)\n"); @@ -963,10 +955,10 @@ static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid) return 0; } -static int cset(int argc, char *argv[], int roflag) +static int cset(int argc, char *argv[], int roflag, int keep_handle) { int err; - snd_ctl_t *handle; + static snd_ctl_t *handle = NULL; snd_ctl_elem_info_t *info; snd_ctl_elem_id_t *id; snd_ctl_elem_value_t *control; @@ -991,12 +983,15 @@ static int cset(int argc, char *argv[], int roflag) show_control_id(id); printf("\n"); } - if ((err = snd_ctl_open(&handle, card, 0)) < 0) { + if (handle == NULL && + (err = snd_ctl_open(&handle, card, 0)) < 0) { error("Control %s open error: %s\n", card, snd_strerror(err)); return err; } snd_ctl_elem_info_set_id(info, id); if ((err = snd_ctl_elem_info(handle, info)) < 0) { + if (ignore_error) + return 0; error("Cannot find the given element from control %s\n", card); return err; } @@ -1060,11 +1055,16 @@ static int cset(int argc, char *argv[], int roflag) ptr++; } if ((err = snd_ctl_elem_write(handle, control)) < 0) { + if (ignore_error) + return 0; error("Control %s element write error: %s\n", card, snd_strerror(err)); return err; } } - snd_ctl_close(handle); + if (! keep_handle) { + snd_ctl_close(handle); + handle = NULL; + } if (!quiet) { snd_hctl_t *hctl; snd_hctl_elem_t *elem; @@ -1163,7 +1163,7 @@ static int get_enum_item_index(snd_mixer_elem_t *elem, char **ptrp) return -1; } -static int sset(unsigned int argc, char *argv[], int roflag) +static int sset(unsigned int argc, char *argv[], int roflag, int keep_handle) { int err; unsigned int idx; @@ -1171,7 +1171,7 @@ static int sset(unsigned int argc, char *argv[], int roflag) unsigned int channels = ~0U; unsigned int dir = 3, okflag = 3; long pmin, pmax, cmin, cmax; - snd_mixer_t *handle; + static snd_mixer_t *handle = NULL; snd_mixer_elem_t *elem; snd_mixer_selem_id_t *sid; snd_mixer_selem_id_alloca(&sid); @@ -1188,30 +1188,38 @@ static int sset(unsigned int argc, char *argv[], int roflag) fprintf(stderr, "Specify what you want to set...\n"); return 1; } - if ((err = snd_mixer_open(&handle, 0)) < 0) { - error("Mixer %s open error: %s\n", card, snd_strerror(err)); - return err; - } - if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { - error("Mixer attach %s error: %s", card, snd_strerror(err)); - snd_mixer_close(handle); - return err; - } - if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { - error("Mixer register error: %s", snd_strerror(err)); - snd_mixer_close(handle); - return err; - } - err = snd_mixer_load(handle); - if (err < 0) { - error("Mixer %s load error: %s", card, snd_strerror(err)); - snd_mixer_close(handle); - return err; + if (handle == NULL) { + if ((err = snd_mixer_open(&handle, 0)) < 0) { + error("Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { + error("Mixer attach %s error: %s", card, snd_strerror(err)); + snd_mixer_close(handle); + handle = NULL; + return err; + } + if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { + error("Mixer register error: %s", snd_strerror(err)); + snd_mixer_close(handle); + handle = NULL; + return err; + } + err = snd_mixer_load(handle); + if (err < 0) { + error("Mixer %s load error: %s", card, snd_strerror(err)); + snd_mixer_close(handle); + handle = NULL; + return err; + } } elem = snd_mixer_find_selem(handle, sid); if (!elem) { + if (ignore_error) + return 0; error("Unable to find simple control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); snd_mixer_close(handle); + handle = NULL; return -ENOENT; } if (roflag) @@ -1319,12 +1327,17 @@ static int sset(unsigned int argc, char *argv[], int roflag) } } if (okflag == 0) { - if (dir & 1) - error("Unknown playback setup '%s'..\n", ptr); - if (dir & 2) - error("Unknown capture setup '%s'..\n", ptr); - snd_mixer_close(handle); - return err; + if (debugflag) { + if (dir & 1) + error("Unknown playback setup '%s'..\n", ptr); + if (dir & 2) + error("Unknown capture setup '%s'..\n", ptr); + } + if (! keep_handle) { + snd_mixer_close(handle); + handle = NULL; + } + return 0; } if (!multi) ptr = optr; @@ -1336,7 +1349,10 @@ static int sset(unsigned int argc, char *argv[], int roflag) printf("Simple mixer control '%s',%i\n", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid)); show_selem(handle, sid, " ", 1); } - snd_mixer_close(handle); + if (! keep_handle) { + snd_mixer_close(handle); + handle = NULL; + } return 0; } @@ -1522,20 +1538,93 @@ static int sevents(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED) return 0; } +/* + * split a line into tokens + * the content in the line buffer is modified + */ +static int split_line(char *buf, char **token, int max_token) +{ + char *dst; + int n, esc, quote; + + for (n = 0; n < max_token; n++) { + while (isspace(*buf)) + buf++; + if (! *buf || *buf == '\n') + return n; + /* skip comments */ + if (*buf == '#' || *buf == '!') + return n; + esc = 0; + quote = 0; + token[n] = buf; + for (dst = buf; *buf && *buf != '\n'; buf++) { + if (esc) + esc = 0; + else if (isspace(*buf) && !quote) { + buf++; + break; + } else if (*buf == '\\') { + esc = 1; + continue; + } else if (*buf == '\'' || *buf == '"') { + if (! quote) { + quote = *buf; + continue; + } else if (*buf == quote) { + quote = 0; + continue; + } + } + *dst++ = *buf; + } + *dst = 0; + } + return n; +} + +#define MAX_ARGS 32 + +static int exec_stdin(void) +{ + int narg; + char buf[256], *args[MAX_ARGS]; + int err = 0; + + /* quiet = 1; */ + ignore_error = 1; + + while (fgets(buf, sizeof(buf), stdin)) { + narg = split_line(buf, args, MAX_ARGS); + if (narg > 0) { + if (!strcmp(args[0], "sset") || !strcmp(args[0], "set")) + err = sset(narg - 1, args + 1, 0, 1); + else if (!strcmp(args[0], "cset")) + err = cset(narg - 1, args + 1, 0, 1); + if (err < 0) + return 1; + } + } + return 0; +} + + int main(int argc, char *argv[]) { int morehelp, level = 0; - struct option long_option[] = + int read_stdin = 0; + static struct option long_option[] = { - {"help", 0, NULL, HELPID_HELP}, - {"card", 1, NULL, HELPID_CARD}, - {"device", 1, NULL, HELPID_DEVICE}, - {"quiet", 0, NULL, HELPID_QUIET}, - {"inactive", 0, NULL, HELPID_INACTIVE}, - {"debug", 0, NULL, HELPID_DEBUG}, - {"nocheck", 0, NULL, HELPID_NOCHECK}, - {"version", 0, NULL, HELPID_VERSION}, - {"abstract", 1, NULL, HELPID_ABSTRACT}, + {"help", 0, NULL, 'h'}, + {"card", 1, NULL, 'c'}, + {"device", 1, NULL, 'D'}, + {"quiet", 0, NULL, 'q'}, + {"inactive", 0, NULL, 'i'}, + {"debug", 0, NULL, 'd'}, + {"nocheck", 0, NULL, 'n'}, + {"version", 0, NULL, 'v'}, + {"abstract", 1, NULL, 'a'}, + {"stdin", 0, NULL, 's'}, {NULL, 0, NULL, 0}, }; @@ -1543,15 +1632,13 @@ int main(int argc, char *argv[]) while (1) { int c; - if ((c = getopt_long(argc, argv, "hc:D:qidnva:", long_option, NULL)) < 0) + if ((c = getopt_long(argc, argv, "hc:D:qidnva:s", long_option, NULL)) < 0) break; switch (c) { case 'h': - case HELPID_HELP: help(); return 0; case 'c': - case HELPID_CARD: { int i; i = snd_card_get_index(optarg); @@ -1564,32 +1651,25 @@ int main(int argc, char *argv[]) } break; case 'D': - case HELPID_DEVICE: strncpy(card, optarg, sizeof(card)-1); card[sizeof(card)-1] = '\0'; break; case 'q': - case HELPID_QUIET: quiet = 1; break; case 'i': - case HELPID_INACTIVE: level |= LEVEL_INACTIVE; break; case 'd': - case HELPID_DEBUG: debugflag = 1; break; case 'n': - case HELPID_NOCHECK: no_check = 1; break; case 'v': - case HELPID_VERSION: printf("amixer version " SND_UTIL_VERSION_STR "\n"); return 1; case 'a': - case HELPID_ABSTRACT: smixer_level = 1; memset(&smixer_options, 0, sizeof(smixer_options)); smixer_options.ver = 1; @@ -1602,6 +1682,9 @@ int main(int argc, char *argv[]) morehelp++; } break; + case 's': + read_stdin = 1; + break; default: fprintf(stderr, "\07Invalid switch or option needs an argument.\n"); morehelp++; @@ -1612,6 +1695,10 @@ int main(int argc, char *argv[]) return 1; } smixer_options.device = card; + + if (read_stdin) + return exec_stdin(); + if (argc - optind <= 0) { return selems(LEVEL_BASIC | level) ? 1 : 0; } @@ -1628,13 +1715,13 @@ int main(int argc, char *argv[]) } else if (!strcmp(argv[optind], "scontents")) { return selems(LEVEL_BASIC | level) ? 1 : 0; } else if (!strcmp(argv[optind], "sset") || !strcmp(argv[optind], "set")) { - return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0) ? 1 : 0; + return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0; } else if (!strcmp(argv[optind], "sget") || !strcmp(argv[optind], "get")) { - return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1) ? 1 : 0; + return sset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0; } else if (!strcmp(argv[optind], "cset")) { - return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0) ? 1 : 0; + return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 0, 0) ? 1 : 0; } else if (!strcmp(argv[optind], "cget")) { - return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1) ? 1 : 0; + return cset(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL, 1, 0) ? 1 : 0; } else if (!strcmp(argv[optind], "events")) { return events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL); } else if (!strcmp(argv[optind], "sevents")) {