split source per command and added command 'names'

- sources are splitted to separate files
- added initial code for 'names' command
This commit is contained in:
Jaroslav Kysela 2005-05-10 10:55:24 +00:00
parent 50414b817e
commit 31efc323b1
7 changed files with 1998 additions and 1414 deletions

View file

@ -2,4 +2,5 @@ sbin_PROGRAMS=alsactl
man_MANS=alsactl.1 man_MANS=alsactl.1
EXTRA_DIST=alsactl.1 EXTRA_DIST=alsactl.1
alsactl_SOURCES=alsactl.c alsactl_SOURCES=alsactl.c state.c power.c names.c

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] <card # or id> \fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fInames\fP] <card # or id>
.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
@ -14,14 +14,19 @@ you have come to the right place.
.SH INVOKING .SH INVOKING
\fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP] <card # or id> \fBalsactl\fP [\fIoptions\fP] [\fIstore\fP|\fIrestore\fP|\fInames\fP] <card # or id>
.SS Commands .SS Commands
\fIstore\fP saves the current driver state for the selected soundcard \fIstore\fP saves the current driver state for the selected soundcard
to the configuration file. to the configuration file.
\fIrestore\fP loads driver state for the selected soundcard from the configuration file. \fIrestore\fP loads driver state for the selected soundcard from the
configuration file.
\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.
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.
@ -34,7 +39,8 @@ Help: show available flags and commands.
.TP .TP
\fI\-f, \-\-file\fP \fI\-f, \-\-file\fP
Select the configuration file to use. The default is /etc/asound.state Select the configuration file to use. The default is /etc/asound.state or
/etc/asound.names (for the \fInames\fP command).
.TP .TP
\fI\-F, \-\-force\fP \fI\-F, \-\-force\fP
@ -63,6 +69,13 @@ 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),

File diff suppressed because it is too large Load diff

22
alsactl/alsactl.h Normal file
View file

@ -0,0 +1,22 @@
extern int debugflag;
extern int force_restore;
extern char *command;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
#define error(...) do {\
fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
fprintf(stderr, __VA_ARGS__); \
putc('\n', stderr); \
} while (0)
#else
#define error(args...) do {\
fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
fprintf(stderr, ##args); \
putc('\n', stderr); \
} while (0)
#endif
int save_state(const char *file, const char *cardname);
int load_state(const char *file, const char *cardname);
int power(const char *argv[], int argc);
int generate_names(const char *cfgfile);

492
alsactl/names.c Normal file
View file

@ -0,0 +1,492 @@
/*
* Advanced Linux Sound Architecture Control Program - ALSA Device Names
* Copyright (c) 2005 by Jaroslav Kysela <perex@suse.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",
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) /* 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_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;
char *flag;
int first = 1, idx;
static const char *vnames1[] = {
"default:%i", "Default Device",
NULL
};
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);
if (err1 == 0 && err2 == 0)
flag = "Duplex";
else if (err1 == 0)
flag = "Output";
else {
flag = "Input";
dname = snd_rawmidi_info_get_name(info2);
}
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;
}
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 = 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, "seq", "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) {
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", cfgfile);
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;
}

200
alsactl/power.c Normal file
View file

@ -0,0 +1,200 @@
/*
* Advanced Linux Sound Architecture Control Program
* Copyright (c) Jaroslav Kysela <perex@suse.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"
static int get_int_state(const char *str)
{
if (!strcasecmp(str, "on"))
return SND_CTL_POWER_D0;
if (!strcasecmp(str, "off"))
return SND_CTL_POWER_D3hot;
if (*str == 'D' || *str == 'd') {
str++;
if (!strcmp(str, "0"))
return SND_CTL_POWER_D0;
if (!strcmp(str, "1"))
return SND_CTL_POWER_D1;
if (!strcmp(str, "2"))
return SND_CTL_POWER_D2;
if (!strcmp(str, "3"))
return SND_CTL_POWER_D3;
if (!strcmp(str, "3hot"))
return SND_CTL_POWER_D3hot;
if (!strcmp(str, "3cold"))
return SND_CTL_POWER_D3cold;
}
return -1;
}
static const char *get_str_state(int power_state)
{
static char str[16];
switch (power_state) {
case SND_CTL_POWER_D0:
return "D0";
case SND_CTL_POWER_D1:
return "D1";
case SND_CTL_POWER_D2:
return "D2";
// return SND_CTL_POWER_D3; /* it's same as D3hot */
case SND_CTL_POWER_D3hot:
return "D3hot";
case SND_CTL_POWER_D3cold:
return "D3cold";
default:
sprintf(str, "???0x%x", power_state);
return str;
}
}
static int show_power(int cardno)
{
snd_ctl_t *handle;
char name[16];
unsigned int power_state;
int err;
sprintf(name, "hw:%d", cardno);
err = snd_ctl_open(&handle, name, 0);
if (err < 0) {
error("snd_ctl_open error: %s", snd_strerror(err));
return err;
}
err = snd_ctl_get_power_state(handle, &power_state);
if (err < 0) {
error("snd_ctl_get_power_state error: %s", snd_strerror(err));
snd_ctl_close(handle);
return err;
}
snd_ctl_close(handle);
printf("Power state for card #%d is %s\n", cardno, get_str_state(power_state));
return 0;
}
static int set_power(int cardno, unsigned int power_state)
{
snd_ctl_t *handle;
char name[16];
int err;
sprintf(name, "hw:%d", cardno);
err = snd_ctl_open(&handle, name, 0);
if (err < 0) {
error("snd_ctl_open error: %s", snd_strerror(err));
return err;
}
err = snd_ctl_set_power_state(handle, power_state);
if (err < 0) {
error("snd_ctl_set_power_state error: %s", snd_strerror(err));
snd_ctl_close(handle);
return err;
}
err = snd_ctl_get_power_state(handle, &power_state);
if (err < 0) {
error("snd_ctl_get_power_state error: %s", snd_strerror(err));
snd_ctl_close(handle);
return err;
}
snd_ctl_close(handle);
printf("Power state for card #%d is %s\n", cardno, get_str_state(power_state));
return 0;
}
int power(const char *argv[], int argc)
{
int power_state, err;
if (argc == 0) { /* show status only */
int card, first = 1;
card = -1;
/* find each installed soundcards */
while (1) {
if (snd_card_next(&card) < 0)
break;
if (card < 0) {
if (first) {
error("No soundcards found...");
return -ENODEV;
}
break;
}
first = 0;
if ((err = show_power(card)) < 0)
return err;
}
return 0;
}
power_state = get_int_state(argv[0]);
if (power_state >= 0) {
int card, first = 1;
card = -1;
/* find each installed soundcards */
while (1) {
if (snd_card_next(&card) < 0)
break;
if (card < 0) {
if (first) {
error("No soundcards found...");
return -ENODEV;
}
break;
}
first = 0;
if ((err = set_power(card, power_state)))
return err;
}
} else {
int cardno;
cardno = snd_card_get_index(argv[0]);
if (cardno < 0) {
error("Cannot find soundcard '%s'...", argv[0]);
return -ENODEV;
}
if (argc > 1) {
power_state = get_int_state(argv[1]);
if (power_state < 0) {
error("Invalid power state '%s'...", argv[1]);
return -EINVAL;
}
if ((err = set_power(cardno, power_state)) < 0)
return err;
} else {
if ((err = show_power(cardno)) < 0)
return err;
}
}
return 0;
}

1258
alsactl/state.c Normal file

File diff suppressed because it is too large Load diff