amixer - Add -s option

- Add -s option to read from stdin the command sequentially.
- Suppress unneeded warnings in sset.
This commit is contained in:
Takashi Iwai 2005-12-01 11:32:28 +00:00
parent 9fe49dd30f
commit 21b94bc276
2 changed files with 172 additions and 76 deletions

View file

@ -2,7 +2,7 @@
.SH NAME .SH NAME
amixer \- command-line mixer for ALSA soundcard driver amixer \- command-line mixer for ALSA soundcard driver
.SH SYNOPSIS .SH SYNOPSIS
\fBamixer\fP [\fI\-c\fP card] [\fIcmd\fP] \fBamixer\fP [\fI\-option\fP] [\fIcmd\fP]
.SH DESCRIPTION .SH DESCRIPTION
\fBamixer\fP allows command-line control of the mixer for the ALSA \fBamixer\fP allows command-line control of the mixer for the ALSA
soundcard driver. soundcard driver.
@ -73,16 +73,25 @@ the \fIcset\fP command.
.SH OPTIONS .SH OPTIONS
.TP .TP
[\fI\-c\fP card] \fI\-c\fP card
Select the card number to control. The device name created from this Select the card number to control. The device name created from this
parameter has syntax 'hw:N' where N is specified card number. parameter has syntax 'hw:N' where N is specified card number.
.TP .TP
[\fI\-D\fP device] \fI\-D\fP device
Select the device name to control. The default control name is 'default'. 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 .TP
\fI\-h\fP \fI\-h\fP
Help: show syntax. Help: show syntax.

View file

@ -31,26 +31,17 @@
#include <sys/poll.h> #include <sys/poll.h>
#include "amixer.h" #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_BASIC (1<<0)
#define LEVEL_INACTIVE (1<<1) #define LEVEL_INACTIVE (1<<1)
#define LEVEL_ID (1<<2) #define LEVEL_ID (1<<2)
int quiet = 0; static int quiet = 0;
int debugflag = 0; static int debugflag = 0;
int no_check = 0; static int no_check = 0;
int smixer_level = 0; static int smixer_level = 0;
struct snd_mixer_selem_regopt smixer_options; static int ignore_error = 0;
char card[64] = "default"; static struct snd_mixer_selem_regopt smixer_options;
static char card[64] = "default";
static void error(const char *fmt,...) static void error(const char *fmt,...)
{ {
@ -65,7 +56,7 @@ static void error(const char *fmt,...)
static int help(void) static int help(void)
{ {
printf("Usage: amixer <options> command\n"); printf("Usage: amixer <options> [command]\n");
printf("\nAvailable options:\n"); printf("\nAvailable options:\n");
printf(" -h,--help this help\n"); printf(" -h,--help this help\n");
printf(" -c,--card N select the card\n"); printf(" -c,--card N select the card\n");
@ -76,6 +67,7 @@ static int help(void)
printf(" -q,--quiet be quiet\n"); printf(" -q,--quiet be quiet\n");
printf(" -i,--inactive show also inactive controls\n"); printf(" -i,--inactive show also inactive controls\n");
printf(" -a,--abstract L select abstraction level (none or basic)\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("\nAvailable commands:\n");
printf(" scontrols show all mixer simple controls\n"); printf(" scontrols show all mixer simple controls\n");
printf(" scontents show contents of all mixer simple controls (default command)\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; 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; int err;
snd_ctl_t *handle; static snd_ctl_t *handle = NULL;
snd_ctl_elem_info_t *info; snd_ctl_elem_info_t *info;
snd_ctl_elem_id_t *id; snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *control; snd_ctl_elem_value_t *control;
@ -991,12 +983,15 @@ static int cset(int argc, char *argv[], int roflag)
show_control_id(id); show_control_id(id);
printf("\n"); 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)); error("Control %s open error: %s\n", card, snd_strerror(err));
return err; return err;
} }
snd_ctl_elem_info_set_id(info, id); snd_ctl_elem_info_set_id(info, id);
if ((err = snd_ctl_elem_info(handle, info)) < 0) { 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); error("Cannot find the given element from control %s\n", card);
return err; return err;
} }
@ -1060,11 +1055,16 @@ static int cset(int argc, char *argv[], int roflag)
ptr++; ptr++;
} }
if ((err = snd_ctl_elem_write(handle, control)) < 0) { 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)); error("Control %s element write error: %s\n", card, snd_strerror(err));
return err; return err;
} }
} }
if (! keep_handle) {
snd_ctl_close(handle); snd_ctl_close(handle);
handle = NULL;
}
if (!quiet) { if (!quiet) {
snd_hctl_t *hctl; snd_hctl_t *hctl;
snd_hctl_elem_t *elem; snd_hctl_elem_t *elem;
@ -1163,7 +1163,7 @@ static int get_enum_item_index(snd_mixer_elem_t *elem, char **ptrp)
return -1; 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; int err;
unsigned int idx; unsigned int idx;
@ -1171,7 +1171,7 @@ static int sset(unsigned int argc, char *argv[], int roflag)
unsigned int channels = ~0U; unsigned int channels = ~0U;
unsigned int dir = 3, okflag = 3; unsigned int dir = 3, okflag = 3;
long pmin, pmax, cmin, cmax; long pmin, pmax, cmin, cmax;
snd_mixer_t *handle; static snd_mixer_t *handle = NULL;
snd_mixer_elem_t *elem; snd_mixer_elem_t *elem;
snd_mixer_selem_id_t *sid; snd_mixer_selem_id_t *sid;
snd_mixer_selem_id_alloca(&sid); snd_mixer_selem_id_alloca(&sid);
@ -1188,6 +1188,7 @@ static int sset(unsigned int argc, char *argv[], int roflag)
fprintf(stderr, "Specify what you want to set...\n"); fprintf(stderr, "Specify what you want to set...\n");
return 1; return 1;
} }
if (handle == NULL) {
if ((err = snd_mixer_open(&handle, 0)) < 0) { if ((err = snd_mixer_open(&handle, 0)) < 0) {
error("Mixer %s open error: %s\n", card, snd_strerror(err)); error("Mixer %s open error: %s\n", card, snd_strerror(err));
return err; return err;
@ -1195,23 +1196,30 @@ static int sset(unsigned int argc, char *argv[], int roflag)
if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) { if (smixer_level == 0 && (err = snd_mixer_attach(handle, card)) < 0) {
error("Mixer attach %s error: %s", card, snd_strerror(err)); error("Mixer attach %s error: %s", card, snd_strerror(err));
snd_mixer_close(handle); snd_mixer_close(handle);
handle = NULL;
return err; return err;
} }
if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) { if ((err = snd_mixer_selem_register(handle, smixer_level > 0 ? &smixer_options : NULL, NULL)) < 0) {
error("Mixer register error: %s", snd_strerror(err)); error("Mixer register error: %s", snd_strerror(err));
snd_mixer_close(handle); snd_mixer_close(handle);
handle = NULL;
return err; return err;
} }
err = snd_mixer_load(handle); err = snd_mixer_load(handle);
if (err < 0) { if (err < 0) {
error("Mixer %s load error: %s", card, snd_strerror(err)); error("Mixer %s load error: %s", card, snd_strerror(err));
snd_mixer_close(handle); snd_mixer_close(handle);
handle = NULL;
return err; return err;
} }
}
elem = snd_mixer_find_selem(handle, sid); elem = snd_mixer_find_selem(handle, sid);
if (!elem) { 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)); 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); snd_mixer_close(handle);
handle = NULL;
return -ENOENT; return -ENOENT;
} }
if (roflag) if (roflag)
@ -1319,12 +1327,17 @@ static int sset(unsigned int argc, char *argv[], int roflag)
} }
} }
if (okflag == 0) { if (okflag == 0) {
if (debugflag) {
if (dir & 1) if (dir & 1)
error("Unknown playback setup '%s'..\n", ptr); error("Unknown playback setup '%s'..\n", ptr);
if (dir & 2) if (dir & 2)
error("Unknown capture setup '%s'..\n", ptr); error("Unknown capture setup '%s'..\n", ptr);
}
if (! keep_handle) {
snd_mixer_close(handle); snd_mixer_close(handle);
return err; handle = NULL;
}
return 0;
} }
if (!multi) if (!multi)
ptr = optr; 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)); 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); show_selem(handle, sid, " ", 1);
} }
if (! keep_handle) {
snd_mixer_close(handle); snd_mixer_close(handle);
handle = NULL;
}
return 0; return 0;
} }
@ -1522,20 +1538,93 @@ static int sevents(int argc ATTRIBUTE_UNUSED, char *argv[] ATTRIBUTE_UNUSED)
return 0; 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 main(int argc, char *argv[])
{ {
int morehelp, level = 0; int morehelp, level = 0;
struct option long_option[] = int read_stdin = 0;
static struct option long_option[] =
{ {
{"help", 0, NULL, HELPID_HELP}, {"help", 0, NULL, 'h'},
{"card", 1, NULL, HELPID_CARD}, {"card", 1, NULL, 'c'},
{"device", 1, NULL, HELPID_DEVICE}, {"device", 1, NULL, 'D'},
{"quiet", 0, NULL, HELPID_QUIET}, {"quiet", 0, NULL, 'q'},
{"inactive", 0, NULL, HELPID_INACTIVE}, {"inactive", 0, NULL, 'i'},
{"debug", 0, NULL, HELPID_DEBUG}, {"debug", 0, NULL, 'd'},
{"nocheck", 0, NULL, HELPID_NOCHECK}, {"nocheck", 0, NULL, 'n'},
{"version", 0, NULL, HELPID_VERSION}, {"version", 0, NULL, 'v'},
{"abstract", 1, NULL, HELPID_ABSTRACT}, {"abstract", 1, NULL, 'a'},
{"stdin", 0, NULL, 's'},
{NULL, 0, NULL, 0}, {NULL, 0, NULL, 0},
}; };
@ -1543,15 +1632,13 @@ int main(int argc, char *argv[])
while (1) { while (1) {
int c; 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; break;
switch (c) { switch (c) {
case 'h': case 'h':
case HELPID_HELP:
help(); help();
return 0; return 0;
case 'c': case 'c':
case HELPID_CARD:
{ {
int i; int i;
i = snd_card_get_index(optarg); i = snd_card_get_index(optarg);
@ -1564,32 +1651,25 @@ int main(int argc, char *argv[])
} }
break; break;
case 'D': case 'D':
case HELPID_DEVICE:
strncpy(card, optarg, sizeof(card)-1); strncpy(card, optarg, sizeof(card)-1);
card[sizeof(card)-1] = '\0'; card[sizeof(card)-1] = '\0';
break; break;
case 'q': case 'q':
case HELPID_QUIET:
quiet = 1; quiet = 1;
break; break;
case 'i': case 'i':
case HELPID_INACTIVE:
level |= LEVEL_INACTIVE; level |= LEVEL_INACTIVE;
break; break;
case 'd': case 'd':
case HELPID_DEBUG:
debugflag = 1; debugflag = 1;
break; break;
case 'n': case 'n':
case HELPID_NOCHECK:
no_check = 1; no_check = 1;
break; break;
case 'v': case 'v':
case HELPID_VERSION:
printf("amixer version " SND_UTIL_VERSION_STR "\n"); printf("amixer version " SND_UTIL_VERSION_STR "\n");
return 1; return 1;
case 'a': case 'a':
case HELPID_ABSTRACT:
smixer_level = 1; smixer_level = 1;
memset(&smixer_options, 0, sizeof(smixer_options)); memset(&smixer_options, 0, sizeof(smixer_options));
smixer_options.ver = 1; smixer_options.ver = 1;
@ -1602,6 +1682,9 @@ int main(int argc, char *argv[])
morehelp++; morehelp++;
} }
break; break;
case 's':
read_stdin = 1;
break;
default: default:
fprintf(stderr, "\07Invalid switch or option needs an argument.\n"); fprintf(stderr, "\07Invalid switch or option needs an argument.\n");
morehelp++; morehelp++;
@ -1612,6 +1695,10 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
smixer_options.device = card; smixer_options.device = card;
if (read_stdin)
return exec_stdin();
if (argc - optind <= 0) { if (argc - optind <= 0) {
return selems(LEVEL_BASIC | level) ? 1 : 0; return selems(LEVEL_BASIC | level) ? 1 : 0;
} }
@ -1628,13 +1715,13 @@ int main(int argc, char *argv[])
} else if (!strcmp(argv[optind], "scontents")) { } else if (!strcmp(argv[optind], "scontents")) {
return selems(LEVEL_BASIC | level) ? 1 : 0; return selems(LEVEL_BASIC | level) ? 1 : 0;
} else if (!strcmp(argv[optind], "sset") || !strcmp(argv[optind], "set")) { } 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")) { } 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")) { } 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")) { } 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")) { } else if (!strcmp(argv[optind], "events")) {
return events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL); return events(argc - optind - 1, argc - optind > 1 ? argv + optind + 1 : NULL);
} else if (!strcmp(argv[optind], "sevents")) { } else if (!strcmp(argv[optind], "sevents")) {