diff --git a/alsactl/Makefile.am b/alsactl/Makefile.am index 0faf1c0..3c5902b 100644 --- a/alsactl/Makefile.am +++ b/alsactl/Makefile.am @@ -4,7 +4,7 @@ sbin_PROGRAMS=alsactl man_MANS=alsactl.1 alsactl_init.7 EXTRA_DIST=alsactl.1 alsactl_init.xml -alsactl_SOURCES=alsactl.c state.c names.c utils.c init_parse.c +alsactl_SOURCES=alsactl.c state.c utils.c init_parse.c noinst_HEADERS=alsactl.h %.7: %.xml diff --git a/alsactl/alsactl.1 b/alsactl/alsactl.1 index 48924c2..f9bcaef 100644 --- a/alsactl/alsactl.1 +++ b/alsactl/alsactl.1 @@ -4,7 +4,7 @@ alsactl \- advanced controls for ALSA soundcard driver .SH SYNOPSIS -\fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fInames\fP] +\fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fIinit\fP] .SH DESCRIPTION \fBalsactl\fP is used to control advanced settings for the ALSA @@ -18,11 +18,11 @@ you have come to the right place. to the configuration file. \fIrestore\fP loads driver state for the selected soundcard from the -configuration file. +configuration file. If restoring fails (eventually partly), the init +action is called. -\fInames\fP generates list of available device names for applications. -The card number or id is ignored for this command. The list is always -generated for all available cards. +\fIinit\fP tries to initialize all devices to a default state. If device +is not known, error code 99 is returned. If no soundcards are specified, setup for all cards will be saved or loaded. @@ -33,10 +33,17 @@ loaded. \fI\-h, \-\-help\fP Help: show available flags and commands. +.TP +\fI\-d, \-\-debug\fP +Use debug mode: a bit more verbose. + +.TP +\fI\-v, \-\-version\fP +Print alsactl version number. + .TP \fI\-f, \-\-file\fP -Select the configuration file to use. The default is /etc/asound.state or -/etc/asound.names (for the \fInames\fP command). +Select the configuration file to use. The default is /etc/asound.state. .TP \fI\-F, \-\-force\fP @@ -49,12 +56,22 @@ Used with restore command. Don't restore mismatching control elements. This option was the old default behavior. .TP -\fI\-d, \-\-debug\fP -Use debug mode: a bit more verbose. +\fI\-r, \-\-runstate\fP +Save restore and init state to this file. The file will contain only errors. +Errors are appended with the soundcard id to the end of file. .TP -\fI\-v, \-\-version\fP -Print alsactl version number. +\fI\-R, \-\-remove\fP +Remove runstate file at first. + +.TP +\fI\-E, \-\-env\fP #=# +Set environment variable (useful for init action). + +.TP +\fI\-i, \-\-initfile\fP #=# +The configuration file for init. By default, PREFIX/share/alsa/init/00main +is used. .SH FILES \fI/etc/asound.state\fP (or whatever file you specify with the @@ -70,13 +87,6 @@ necessary for some soundcard features (e.g. enabling/disabling automatic mic gain, digital output, joystick/game ports, some future MIDI routing options, etc). -\fI/etc/asound.names\fP (or whatever file you specify with the -\fB\-f\fP flag) is used to store the list of device names available -in your system. The list does not contain all virtual names, because -the name space is infinite, but it detects present hardware and -generates list of common names. The user / system administrator / another -configuration tool might modify the file to add virtual names as well. - .SH SEE ALSO \fB amixer(1), diff --git a/alsactl/alsactl.c b/alsactl/alsactl.c index 9d79b47..552cfce 100644 --- a/alsactl/alsactl.c +++ b/alsactl/alsactl.c @@ -31,7 +31,6 @@ #include "alsactl.h" #define SYS_ASOUNDRC "/etc/asound.state" -#define SYS_ASOUNDNAMES "/etc/asound.names" int debugflag = 0; int force_restore = 1; @@ -46,12 +45,13 @@ static void help(void) printf(" -d,--debug debug mode\n"); printf(" -v,--version print version of this program\n"); printf("\nAvailable state options:\n"); - printf(" -f,--file # configuration file (default " SYS_ASOUNDRC " or " SYS_ASOUNDNAMES ")\n"); + printf(" -f,--file # configuration file (default " SYS_ASOUNDRC ")\n"); printf(" -F,--force try to restore the matching controls as much as possible\n"); printf(" (default mode)\n"); printf(" -P,--pedantic don't restore mismatching controls (old default)\n"); printf(" -r,--runstate # save restore and init state to this file (only errors)\n"); printf(" default settings is 'no file set'\n"); + printf(" -R,--remove remove runstate file at first, otherwise append errors\n"); printf("\nAvailable init options:\n"); printf(" -E,--env #=# set environment variable for init phase (NAME=VALUE)\n"); printf(" -i,--initfile # main configuation file for init phase (default " DATADIR "/init/00main)\n"); @@ -77,6 +77,7 @@ int main(int argc, char *argv[]) {"force", 0, NULL, 'F'}, {"pedantic", 0, NULL, 'P'}, {"runstate", 0, NULL, 'r'}, + {"remove", 0, NULL, 'R'}, {"debug", 0, NULL, 'd'}, {"version", 0, NULL, 'v'}, {NULL, 0, NULL, 0}, @@ -84,13 +85,14 @@ int main(int argc, char *argv[]) char *cfgfile = SYS_ASOUNDRC; char *initfile = DATADIR "/init/00main"; char *cardname; + int removestate = 0; int res; command = argv[0]; while (1) { int c; - if ((c = getopt_long(argc, argv, "hdvf:FE:i:Pr:", long_option, NULL)) < 0) + if ((c = getopt_long(argc, argv, "hdvf:FE:i:Pr:R", long_option, NULL)) < 0) break; switch (c) { case 'h': @@ -114,6 +116,9 @@ int main(int argc, char *argv[]) case 'r': statefile = optarg; break; + case 'R': + removestate = 1; + break; case 'P': force_restore = 0; break; @@ -143,12 +148,9 @@ int main(int argc, char *argv[]) } else if (!strcmp(argv[optind], "store")) { res = save_state(cfgfile, cardname); } else if (!strcmp(argv[optind], "restore")) { - remove(statefile); + if (removestate) + remove(statefile); res = load_state(cfgfile, initfile, cardname); - } else if (!strcmp(argv[optind], "names")) { - if (!strcmp(cfgfile, SYS_ASOUNDRC)) - cfgfile = SYS_ASOUNDNAMES; - res = generate_names(cfgfile); } else { fprintf(stderr, "alsactl: Unknown command '%s'...\n", argv[optind]); diff --git a/alsactl/names.c b/alsactl/names.c deleted file mode 100644 index c779985..0000000 --- a/alsactl/names.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Advanced Linux Sound Architecture Control Program - ALSA Device Names - * Copyright (c) 2005 by Jaroslav Kysela - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "aconfig.h" -#include "version.h" -#include -#include -#include -#include -#include -#include -#include "alsactl.h" - -typedef int (probe_single)(int card, snd_ctl_t *ctl, snd_config_t *config); - -static int globidx; - -static void dummy_error_handler(const char *file, int line, const char *function, int err, const char *fmt, ...) -{ -} - -static int for_each_card(probe_single *fcn, snd_config_t *config) -{ - int card = -1, first = 1, err; - snd_ctl_t *ctl; - char ctlname[16]; - - while (1) { - if (snd_card_next(&card) < 0) - break; - if (card < 0) { - if (first) { - error("No soundcards found..."); - return -ENODEV; - } - break; - } - first = 0; - sprintf(ctlname, "hw:%i", card); - err = snd_ctl_open(&ctl, ctlname, 0); - if (err < 0) - return err; - err = (fcn)(card, ctl, config); - snd_ctl_close(ctl); - if (err < 0) - return err; - } - return 0; -} - -static int add_entry(snd_config_t *cfg, const char *name, - const char *cprefix, const char *flag, - const char *comment) -{ - int err; - snd_config_t *c, *d; - char id[16]; - char xcomment[256]; - char *flag0 = " (", *flag1 = ")"; - - if (cprefix == NULL) - cprefix = ""; - if (flag == NULL) { - flag0 = ""; - flag = ""; - flag1 = ""; - } - sprintf(xcomment, "%s - %s%s%s%s", cprefix, comment, flag0, flag, flag1); - sprintf(id, "alsactl%i", globidx++); - err = snd_config_make_compound(&c, id, 0); - if (err < 0) - return err; - err = snd_config_add(cfg, c); - if (err < 0) - return err; - err = snd_config_make_string(&d, "name"); - if (err < 0) - return err; - err = snd_config_set_string(d, name); - if (err < 0) - return err; - err = snd_config_add(c, d); - if (err < 0) - return err; - err = snd_config_make_string(&d, "comment"); - if (err < 0) - return err; - err = snd_config_set_string(d, xcomment); - if (err < 0) - return err; - err = snd_config_add(c, d); - if (err < 0) - return err; - return 0; -} - -static int probe_ctl_card(int card, snd_ctl_t *ctl, snd_config_t *config) -{ - int err; - snd_ctl_card_info_t * info; - char name[16]; - const char *dname; - - snd_ctl_card_info_alloca(&info); - err = snd_ctl_card_info(ctl, info); - if (err < 0) { - error("Unable to get info for card %i: %s\n", card, snd_strerror(err)); - return err; - } - sprintf(name, "hw:%i", card); - dname = snd_ctl_card_info_get_longname(info); - err = add_entry(config, name, "Physical Device", NULL, dname); - if (err < 0) - return err; - return 0; -} - -static int probe_ctl(snd_config_t *config) -{ - int err; - snd_config_t *c; - - err = snd_config_make_compound(&c, "ctl", 0); - if (err < 0) - return err; - err = snd_config_add(config, c); - if (err < 0) - return err; - err = for_each_card(probe_ctl_card, c); - if (err < 0) - return err; - return 0; -} - -static int probe_pcm_virtual(int card, snd_ctl_t *ctl, snd_config_t *config, - const char *name, const char *comment) -{ - snd_pcm_t *pcm1, *pcm2; - int err1, err2, playback, capture, err; - char name1[32], name2[32], *flag; - - if (!debugflag) - snd_lib_error_set_handler(dummy_error_handler); - sprintf(name1, name, card); - sprintf(name2, "plug:%s", name1); - err1 = snd_pcm_open(&pcm1, name1, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); - err2 = snd_pcm_open(&pcm2, name1, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); - snd_lib_error_set_handler(NULL); - if (err1 >= 0) - snd_pcm_close(pcm1); - if (err2 >= 0) - snd_pcm_close(pcm2); - playback = (err1 == 0 || err1 == -EBUSY); - capture = (err2 == 0 || err2 == -EBUSY); - if (playback && capture) - flag = "Duplex"; - else if (playback) - flag = "Playback"; - else if (capture) - flag = "Capture"; - else - return 0; - err = add_entry(config, name1, "Abstract Device", flag, comment); - if (err >= 0) - err = add_entry(config, name2, "Abstract Device With Conversions", flag, comment); - return err; -} - -static int probe_pcm_card(int card, snd_ctl_t *ctl, snd_config_t *config) -{ - int dev = -1, err, err1, err2; - snd_pcm_info_t * info1, * info2; - snd_pcm_class_t class; - char name[16]; - const char *dname; - char *flag; - int first = 1, idx; - static const char *vnames1[] = { - "default:%i", "Default Device", - "front:%i", "Front Speakers", - "rear:%i", "Rear Speakers", - NULL - }; - static const char *vnames2[] = { - "surround40:%i", "Front and Rear Speakers", - "surround51:%i", "Front, Rear, Center and Woofer", - "surround71:%i", "Front, Rear, Side, Center and Woofer", - "spdif:%i", "S/PDIF (IEC958) Optical or Coaxial Wire", - "phoneline:%i", "Phone Line Interface", - "modem:%i", "Soft Modem", - NULL - }; - - snd_pcm_info_alloca(&info1); - snd_pcm_info_alloca(&info2); - while (1) { - err = snd_ctl_pcm_next_device(ctl, &dev); - if (err < 0) - return err; - if (dev < 0) - break; - memset(info1, 0, snd_pcm_info_sizeof()); - snd_pcm_info_set_device(info1, dev); - snd_pcm_info_set_stream(info1, SND_PCM_STREAM_PLAYBACK); - err1 = snd_ctl_pcm_info(ctl, info1); - memset(info2, 0, snd_pcm_info_sizeof()); - snd_pcm_info_set_device(info2, dev); - snd_pcm_info_set_stream(info2, SND_PCM_STREAM_CAPTURE); - err2 = snd_ctl_pcm_info(ctl, info2); - if (err1 < 0 && err2 < 0) { - error("Unable to get info for pcm device %i:%i: %s\n", card, dev, snd_strerror(err1)); - continue; - } - dname = snd_pcm_info_get_name(info1); - class = snd_pcm_info_get_class(info1); - if (err1 == 0 && err2 == 0) - flag = "Duplex"; - else if (err1 == 0) - flag = "Playback"; - else { - flag = "Capture"; - dname = snd_pcm_info_get_name(info2); - class = snd_pcm_info_get_class(info2); - } - if (class != SND_PCM_CLASS_GENERIC && - class != SND_PCM_CLASS_MULTI && - class != SND_PCM_CLASS_MODEM ) /* skip this */ - continue; - if (first) { - for (idx = 0; vnames1[idx] != NULL; idx += 2) - probe_pcm_virtual(card, ctl, config, vnames1[idx], vnames1[idx+1]); - } - first = 0; - sprintf(name, "hw:%i,%i", card, dev); - err = add_entry(config, name, "Physical Device", flag, dname); - if (err < 0) - return err; - sprintf(name, "plughw:%i,%i", card, dev); - err = add_entry(config, name, "Physical Device With Conversions", flag, dname); - if (err < 0) - return err; - } - if (!first) { - for (idx = 0; vnames2[idx] != NULL; idx += 2) - probe_pcm_virtual(card, ctl, config, vnames2[idx], vnames2[idx+1]); - } - return 0; -} - -static int probe_pcm(snd_config_t *config) -{ - int err; - snd_config_t *c; - - err = snd_config_make_compound(&c, "pcm", 0); - if (err < 0) - return err; - err = snd_config_add(config, c); - if (err < 0) - return err; - err = for_each_card(probe_pcm_card, c); - if (err < 0) - return err; - return 0; -} - -static int probe_rawmidi_virtual(snd_config_t *config, - const char *name, const char *comment) -{ - snd_rawmidi_t *rawmidi1, *rawmidi2; - int err1, err2, playback, capture, err; - char *flag; - - if (!debugflag) - snd_lib_error_set_handler(dummy_error_handler); - err1 = snd_rawmidi_open(NULL, &rawmidi1, name, SND_RAWMIDI_NONBLOCK); - err2 = snd_rawmidi_open(&rawmidi2, NULL, name, SND_RAWMIDI_NONBLOCK); - snd_lib_error_set_handler(NULL); - if (err1 >= 0) - snd_rawmidi_close(rawmidi1); - if (err2 >= 0) - snd_rawmidi_close(rawmidi2); - playback = (err1 == 0 || err1 == -EBUSY); - capture = (err2 == 0 || err2 == -EBUSY); - if (playback && capture) - flag = "Duplex"; - else if (playback) - flag = "Playback"; - else if (capture) - flag = "Capture"; - else - return 0; - err = add_entry(config, name, "Abstract Device", flag, comment); - return err; -} - -static int probe_rawmidi_card(int card, snd_ctl_t *ctl, snd_config_t *config) -{ - int dev = -1, err, err1, err2; - snd_rawmidi_info_t * info1, * info2; - char name[16]; - const char *dname; - const char *subname; - char *flag; - int subdev; - - snd_rawmidi_info_alloca(&info1); - snd_rawmidi_info_alloca(&info2); - while (1) { - err = snd_ctl_rawmidi_next_device(ctl, &dev); - if (err < 0) - return err; - if (dev < 0) - break; - memset(info1, 0, snd_rawmidi_info_sizeof()); - snd_rawmidi_info_set_device(info1, dev); - snd_rawmidi_info_set_stream(info1, SND_RAWMIDI_STREAM_OUTPUT); - err1 = snd_ctl_rawmidi_info(ctl, info1); - memset(info2, 0, snd_rawmidi_info_sizeof()); - snd_rawmidi_info_set_device(info2, dev); - snd_rawmidi_info_set_stream(info2, SND_RAWMIDI_STREAM_INPUT); - err2 = snd_ctl_rawmidi_info(ctl, info2); - if (err1 < 0 && err2 < 0) { - error("Unable to get info for rawmidi device %i:%i: %s\n", card, dev, snd_strerror(err1)); - continue; - } - dname = snd_rawmidi_info_get_name(info1); - subname = snd_rawmidi_info_get_subdevice_name(info1); - if (err1 == 0 && err2 == 0) - flag = "Duplex"; - else if (err1 == 0) - flag = "Output"; - else { - flag = "Input"; - dname = snd_rawmidi_info_get_name(info2); - subname = snd_rawmidi_info_get_subdevice_name(info2); - } - if (subname[0] == '\0') { - sprintf(name, "hw:%i,%i", card, dev); - err = add_entry(config, name, "Physical Device", flag, dname); - if (err < 0) - return err; - } else { - subdev = 0; - do { - sprintf(name, "hw:%i,%i,%i", card, dev, subdev); - if (err1 == 0) - subname = snd_rawmidi_info_get_subdevice_name(info1); - else - subname = snd_rawmidi_info_get_subdevice_name(info2); - if (err1 == 0 && err2 == 0) - flag = "Duplex"; - else if (err1 == 0) - flag = "Output"; - else - flag = "Input"; - err = add_entry(config, name, "Physical Device", flag, subname); - if (err < 0) - return err; - ++subdev; - snd_rawmidi_info_set_subdevice(info1, subdev); - snd_rawmidi_info_set_subdevice(info2, subdev); - err1 = snd_ctl_rawmidi_info(ctl, info1); - err2 = snd_ctl_rawmidi_info(ctl, info2); - } while (err1 == 0 || err2 == 0); - } - } - return 0; -} - -static int probe_rawmidi(snd_config_t *config) -{ - int err; - snd_config_t *c; - - err = snd_config_make_compound(&c, "rawmidi", 0); - if (err < 0) - return err; - err = snd_config_add(config, c); - if (err < 0) - return err; - err = probe_rawmidi_virtual(c, "default", "Default Device"); - if (err < 0) - return err; - err = for_each_card(probe_rawmidi_card, c); - if (err < 0) - return err; - err = add_entry(c, "virtual", "Virtual Device", "Duplex", "Sequencer"); - if (err < 0) - return err; - err = add_entry(c, "virtual:MERGE=0", "Virtual Device", "Duplex", "Sequencer (No Merge)"); - if (err < 0) - return err; - return 0; -} - -static int probe_timers(snd_config_t *config) -{ - int err; - snd_timer_query_t *handle; - snd_timer_id_t *id; - snd_timer_ginfo_t *info; - char name[64]; - const char *dname; - - err = snd_timer_query_open(&handle, "default", 0); - if (err < 0) - return err; - snd_timer_id_alloca(&id); - snd_timer_ginfo_alloca(&info); - snd_timer_id_set_class(id, SND_TIMER_CLASS_NONE); - while (1) { - err = snd_timer_query_next_device(handle, id); - if (err < 0) - goto _err; - if (snd_timer_id_get_class(id) < 0) - break; - if (snd_timer_id_get_class(id) == SND_TIMER_CLASS_PCM) - continue; - snd_timer_ginfo_set_tid(info, id); - err = snd_timer_query_info(handle, info); - if (err < 0) - continue; - sprintf(name, "hw:CLASS=%i,SCLASS=%i,CARD=%i,DEV=%i,SUBDEV=%i", - snd_timer_id_get_class(id), - snd_timer_id_get_sclass(id), - snd_timer_id_get_card(id), - snd_timer_id_get_device(id), - snd_timer_id_get_subdevice(id)); - dname = snd_timer_ginfo_get_name(info); - err = add_entry(config, name, "Physical Device", NULL, dname); - if (err < 0) - goto _err; - } - err = 0; - _err: - snd_timer_query_close(handle); - return err; -} - -static int probe_timer(snd_config_t *config) -{ - int err; - snd_config_t *c; - - err = snd_config_make_compound(&c, "timer", 0); - if (err < 0) - return err; - err = snd_config_add(config, c); - if (err < 0) - return err; - err = probe_timers(c); - if (err < 0) - return err; - return 0; -} - -static int probe_seq(snd_config_t *config) -{ - int err; - snd_config_t *c; - - err = snd_config_make_compound(&c, "seq", 0); - if (err < 0) - return err; - err = snd_config_add(config, c); - if (err < 0) - return err; - err = add_entry(c, "default", "Default Device", "Duplex", "Sequencer"); - if (err < 0) - return err; - err = add_entry(c, "hw", "Physical Device", "Duplex", "Sequencer"); - if (err < 0) - return err; - return 0; -} - -typedef int (probe_fcn)(snd_config_t *config); - -static probe_fcn * probes[] = { - probe_ctl, - probe_pcm, - probe_rawmidi, - probe_timer, - probe_seq, - NULL -}; - -int generate_names(const char *cfgfile) -{ - int err, idx; - snd_config_t *config; - snd_output_t *out; - int stdio, ok = 0; - - err = snd_config_top(&config); - if (err < 0) { - error("snd_config_top error: %s", snd_strerror(err)); - return err; - } - for (idx = 0; probes[idx]; idx++) { - globidx = 1; - err = (probes[idx])(config); - if (err < 0) { - /* ignore -ENOTTY indicating the non-existing component */ - if (err != -ENOTTY) - error("probe %i failed: %s", idx, snd_strerror(err)); - } else { - ok++; - } - } - if (ok > 0) { - stdio = !strcmp(cfgfile, "-"); - if (stdio) { - err = snd_output_stdio_attach(&out, stdout, 0); - } else { - err = snd_output_stdio_open(&out, cfgfile, "w+"); - } - if (err < 0) { - error("Cannot open %s for writing: %s", cfgfile, snd_strerror(err)); - return -errno; - } - err = snd_config_save(config, out); - snd_output_close(out); - if (err < 0) - error("snd_config_save: %s", snd_strerror(err)); - } else { - return -ENOENT; - } - return 0; -}