mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-10 00:25:43 +01:00
alsactl - remove 'names' command, fix alsactl man page
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
a227a9ad52
commit
ef8bfcecda
4 changed files with 39 additions and 576 deletions
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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]);
|
||||||
|
|
549
alsactl/names.c
549
alsactl/names.c
|
@ -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;
|
|
||||||
}
|
|
Loading…
Reference in a new issue