alsactl: add dump-cfg and dump-state commands

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2021-03-07 19:58:33 +01:00
parent 09c04f8935
commit c1474594dc
8 changed files with 103 additions and 34 deletions

View file

@ -41,6 +41,10 @@ control device.
\fIclean\fP clean the controls created by applications.
\fIdump-state\fP dump the current state (all cards).
\fIdump-cfg\fP dump the current configuration (all cards, hooks are evaluated).
If no soundcards are specified, setup for all cards will be saved,
loaded or monitored.

View file

@ -29,7 +29,6 @@
#include <errno.h>
#include <syslog.h>
#include <sched.h>
#include <alsa/asoundlib.h>
#include "alsactl.h"
#ifndef SYS_ASOUNDRC
@ -111,6 +110,8 @@ static struct arg args[] = {
{ CARDCMD, "rdaemon", "like daemon but do the state restore at first" },
{ KILLCMD, "kill", "notify daemon to quit, rescan or save_and_quit" },
{ CARDCMD, "monitor", "monitor control events" },
{ EMPCMD, "dump-state", "dump the state (for all cards)" },
{ EMPCMD, "dump-cfg", "dump the configuration (expanded, for all cards)" },
{ 0, NULL, NULL }
};
@ -139,7 +140,7 @@ static void help(void)
strcat(buf, "<card>");
else if (sarg & KILLCMD)
strcat(buf, "<cmd>");
printf(" %-8s %-6s %s\n", larg ? larg : "",
printf(" %-10s %-6s %s\n", larg ? larg : "",
buf, a->comment);
continue;
}
@ -154,6 +155,48 @@ static void help(void)
}
}
static int dump_config_tree(snd_config_t *top)
{
snd_output_t *out;
int err;
err = snd_output_stdio_attach(&out, stdout, 0);
if (err < 0)
return err;
err = snd_config_save(top, out);
snd_output_close(out);
return 0;
}
static int dump_state(const char *file)
{
snd_config_t *top;
int err;
err = load_configuration(file, &top, NULL);
if (err < 0)
return err;
err = dump_config_tree(top);
snd_config_delete(top);
snd_config_update_free_global();
return err;
}
static int dump_configuration(void)
{
snd_config_t *top, *cfg2;
int err;
err = snd_config_update_ref(&top);
if (err < 0)
return err;
/* expand cards.* tree */
snd_config_search_definition(top, "cards", "dummy", &cfg2);
err = dump_config_tree(top);
snd_config_unref(top);
return err;
}
#define NO_NICE (-100000)
static void do_nice(int use_nice, int sched_idle)
@ -399,6 +442,10 @@ int main(int argc, char *argv[])
res = monitor(cardname);
} else if (!strcmp(cmd, "clean")) {
res = clean(cardname, extra_args);
} else if (!strcmp(cmd, "dump-state")) {
res = dump_state(cfgfile);
} else if (!strcmp(cmd, "dump-cfg")) {
res = dump_configuration();
} else {
fprintf(stderr, "alsactl: Unknown command '%s'...\n", cmd);
res = -ENODEV;

View file

@ -1,3 +1,5 @@
#include <alsa/asoundlib.h>
extern int debugflag;
extern int force_restore;
extern int ignore_nocards;
@ -28,6 +30,7 @@ void error_handler(const char *file, int line, const char *function, int err, co
#define FLAG_UCM_DISABLED (1<<0)
#define FLAG_UCM_DEFAULTS (1<<1)
int load_configuration(const char *file, snd_config_t **top, int *open_failed);
int init(const char *file, int flags, const char *cardname);
int init_ucm(int flags, int cardno);
int state_lock(const char *file, int timeout);

View file

@ -26,7 +26,6 @@
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#include "alsactl.h"
static int clean_one_control(snd_ctl_t *handle, snd_ctl_elem_id_t *elem_id,

View file

@ -29,7 +29,6 @@
#include <signal.h>
#include <time.h>
#include <poll.h>
#include <alsa/asoundlib.h>
#include "alsactl.h"
struct id_list {

View file

@ -37,7 +37,6 @@
#include <sys/types.h>
#include <dirent.h>
#include <math.h>
#include <alsa/asoundlib.h>
#include "aconfig.h"
#include "alsactl.h"
#include "list.h"

View file

@ -27,7 +27,6 @@
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <alsa/asoundlib.h>
#include "alsactl.h"
@ -1648,38 +1647,17 @@ out:
int load_state(const char *file, const char *initfile, int initflags,
const char *cardname, int do_init)
{
int err, finalerr = 0;
int err, finalerr = 0, open_failed;
snd_config_t *config;
snd_input_t *in;
int stdio, lock_fd = -EINVAL;
err = snd_config_top(&config);
if (err < 0) {
error("snd_config_top error: %s", snd_strerror(err));
err = load_configuration(file, &config, &open_failed);
if (err < 0 && !open_failed)
return err;
}
stdio = !strcmp(file, "-");
if (stdio) {
err = snd_input_stdio_attach(&in, stdin, 0);
} else {
lock_fd = state_lock(file, 10);
err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd;
}
if (err >= 0) {
err = snd_config_load(config, in);
snd_input_close(in);
if (lock_fd >= 0)
state_unlock(lock_fd, file);
if (err < 0) {
error("snd_config_load error: %s", snd_strerror(err));
goto out;
}
} else {
if (open_failed) {
int card, first = 1;
char cardname1[16];
if (lock_fd >= 0)
state_unlock(lock_fd, file);
error("Cannot open %s for reading: %s", file, snd_strerror(err));
finalerr = err;
if (cardname) {

View file

@ -30,8 +30,6 @@
#include <syslog.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <alsa/asoundlib.h>
#include "alsactl.h"
int file_map(const char *filename, char **buf, size_t *bufsize)
@ -193,3 +191,45 @@ void error_handler(const char *file, int line, const char *function, int err, co
fprintf(stderr, "alsa-lib %s:%i:(%s) %s%s%s\n", file, line, function,
buf, err ? ": " : "", err ? snd_strerror(err) : "");
}
int load_configuration(const char *file, snd_config_t **top, int *open_failed)
{
snd_config_t *config;
snd_input_t *in;
int err, stdio_flag, lock_fd = -EINVAL;
*top = NULL;
if (open_failed)
*open_failed = 0;
err = snd_config_top(&config);
if (err < 0) {
error("snd_config_top error: %s", snd_strerror(err));
return err;
}
stdio_flag = !strcmp(file, "-");
if (stdio_flag) {
err = snd_input_stdio_attach(&in, stdin, 0);
} else {
lock_fd = state_lock(file, 10);
err = lock_fd >= 0 ? snd_input_stdio_open(&in, file, "r") : lock_fd;
}
if (err < 0) {
if (open_failed)
*open_failed = 1;
goto out;
}
err = snd_config_load(config, in);
snd_input_close(in);
if (lock_fd >= 0)
state_unlock(lock_fd, file);
if (err < 0) {
error("snd_config_load error: %s", snd_strerror(err));
out:
snd_config_delete(config);
snd_config_update_free_global();
return err;
} else {
*top = config;
return 0;
}
}