alsactl - remove 'names' command, fix alsactl man page

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2008-08-18 16:47:33 +02:00
parent a227a9ad52
commit ef8bfcecda
4 changed files with 39 additions and 576 deletions

View file

@ -4,7 +4,7 @@ sbin_PROGRAMS=alsactl
man_MANS=alsactl.1 alsactl_init.7 man_MANS=alsactl.1 alsactl_init.7
EXTRA_DIST=alsactl.1 alsactl_init.xml 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 noinst_HEADERS=alsactl.h
%.7: %.xml %.7: %.xml

View file

@ -4,7 +4,7 @@ alsactl \- advanced controls for ALSA soundcard driver
.SH SYNOPSIS .SH SYNOPSIS
\fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fInames\fP] <card # or id> \fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fIinit\fP] <card # or id or device>
.SH DESCRIPTION .SH DESCRIPTION
\fBalsactl\fP is used to control advanced settings for the ALSA \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. to the configuration file.
\fIrestore\fP loads driver state for the selected soundcard from the \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. \fIinit\fP tries to initialize all devices to a default state. If device
The card number or id is ignored for this command. The list is always is not known, error code 99 is returned.
generated for all available cards.
If no soundcards are specified, setup for all cards will be saved or If no soundcards are specified, setup for all cards will be saved or
loaded. loaded.
@ -33,10 +33,17 @@ loaded.
\fI\-h, \-\-help\fP \fI\-h, \-\-help\fP
Help: show available flags and commands. 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 .TP
\fI\-f, \-\-file\fP \fI\-f, \-\-file\fP
Select the configuration file to use. The default is /etc/asound.state or Select the configuration file to use. The default is /etc/asound.state.
/etc/asound.names (for the \fInames\fP command).
.TP .TP
\fI\-F, \-\-force\fP \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. This option was the old default behavior.
.TP .TP
\fI\-d, \-\-debug\fP \fI\-r, \-\-runstate\fP
Use debug mode: a bit more verbose. 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 .TP
\fI\-v, \-\-version\fP \fI\-R, \-\-remove\fP
Print alsactl version number. 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 .SH FILES
\fI/etc/asound.state\fP (or whatever file you specify with the \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 automatic mic gain, digital output, joystick/game ports, some future MIDI
routing options, etc). 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 .SH SEE ALSO
\fB \fB
amixer(1), amixer(1),

View file

@ -31,7 +31,6 @@
#include "alsactl.h" #include "alsactl.h"
#define SYS_ASOUNDRC "/etc/asound.state" #define SYS_ASOUNDRC "/etc/asound.state"
#define SYS_ASOUNDNAMES "/etc/asound.names"
int debugflag = 0; int debugflag = 0;
int force_restore = 1; int force_restore = 1;
@ -46,12 +45,13 @@ static void help(void)
printf(" -d,--debug debug mode\n"); printf(" -d,--debug debug mode\n");
printf(" -v,--version print version of this program\n"); printf(" -v,--version print version of this program\n");
printf("\nAvailable state options:\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(" -F,--force try to restore the matching controls as much as possible\n");
printf(" (default mode)\n"); printf(" (default mode)\n");
printf(" -P,--pedantic don't restore mismatching controls (old default)\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(" -r,--runstate # save restore and init state to this file (only errors)\n");
printf(" default settings is 'no file set'\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("\nAvailable init options:\n");
printf(" -E,--env #=# set environment variable for init phase (NAME=VALUE)\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"); 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'}, {"force", 0, NULL, 'F'},
{"pedantic", 0, NULL, 'P'}, {"pedantic", 0, NULL, 'P'},
{"runstate", 0, NULL, 'r'}, {"runstate", 0, NULL, 'r'},
{"remove", 0, NULL, 'R'},
{"debug", 0, NULL, 'd'}, {"debug", 0, NULL, 'd'},
{"version", 0, NULL, 'v'}, {"version", 0, NULL, 'v'},
{NULL, 0, NULL, 0}, {NULL, 0, NULL, 0},
@ -84,13 +85,14 @@ int main(int argc, char *argv[])
char *cfgfile = SYS_ASOUNDRC; char *cfgfile = SYS_ASOUNDRC;
char *initfile = DATADIR "/init/00main"; char *initfile = DATADIR "/init/00main";
char *cardname; char *cardname;
int removestate = 0;
int res; int res;
command = argv[0]; command = argv[0];
while (1) { while (1) {
int c; 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; break;
switch (c) { switch (c) {
case 'h': case 'h':
@ -114,6 +116,9 @@ int main(int argc, char *argv[])
case 'r': case 'r':
statefile = optarg; statefile = optarg;
break; break;
case 'R':
removestate = 1;
break;
case 'P': case 'P':
force_restore = 0; force_restore = 0;
break; break;
@ -143,12 +148,9 @@ int main(int argc, char *argv[])
} else if (!strcmp(argv[optind], "store")) { } else if (!strcmp(argv[optind], "store")) {
res = save_state(cfgfile, cardname); res = save_state(cfgfile, cardname);
} else if (!strcmp(argv[optind], "restore")) { } else if (!strcmp(argv[optind], "restore")) {
remove(statefile); if (removestate)
remove(statefile);
res = load_state(cfgfile, initfile, cardname); 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 { } else {
fprintf(stderr, "alsactl: Unknown command '%s'...\n", fprintf(stderr, "alsactl: Unknown command '%s'...\n",
argv[optind]); argv[optind]);

View file

@ -1,549 +0,0 @@
/*
* Advanced Linux Sound Architecture Control Program - ALSA Device Names
* Copyright (c) 2005 by Jaroslav Kysela <perex@perex.cz>
*
*
* 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 <getopt.h>
#include <stdarg.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#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;
}