mirror of
https://github.com/alsa-project/alsa-utils
synced 2024-11-09 17:45:41 +01:00
alsactl: add 'clean' command to remove the application controls
It is handy to remove all card controls created by applications. This change allows to remove those controls for all cards, selected card or selected card with a control id filter list like: alsactl clean 0 "name='PCM'" "name='Mic Phantom'" Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
parent
c1f8cc2f07
commit
17b4129e6c
6 changed files with 238 additions and 2 deletions
|
@ -10,7 +10,7 @@ EXTRA_DIST=alsactl.1 alsactl_init.xml
|
|||
AM_CFLAGS = -D_GNU_SOURCE
|
||||
|
||||
alsactl_SOURCES=alsactl.c state.c lock.c utils.c init_parse.c init_ucm.c \
|
||||
daemon.c monitor.c
|
||||
daemon.c monitor.c clean.c
|
||||
|
||||
alsactl_CFLAGS=$(AM_CFLAGS) -D__USE_GNU \
|
||||
-DSYS_ASOUNDRC=\"$(ASOUND_STATE_DIR)/asound.state\" \
|
||||
|
|
|
@ -39,6 +39,8 @@ rescan, save_and_quit).
|
|||
\fImonitor\fP is for monitoring the events received from the given
|
||||
control device.
|
||||
|
||||
\fIclean\fP clean the controls created by applications.
|
||||
|
||||
If no soundcards are specified, setup for all cards will be saved,
|
||||
loaded or monitored.
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@ int main(int argc, char *argv[])
|
|||
char *pidfile = SYS_PIDFILE;
|
||||
char *cardname, ncardname[16];
|
||||
char *cmd;
|
||||
char *const *extra_args;
|
||||
const char *const *tmp;
|
||||
int removestate = 0;
|
||||
int init_fallback = 1; /* new default behavior */
|
||||
|
@ -346,6 +347,8 @@ int main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
extra_args = argc - optind > 2 ? argv + optind + 2 : NULL;
|
||||
|
||||
/* the global system file should be always locked */
|
||||
if (strcmp(cfgfile, SYS_ASOUNDRC) == 0 && do_lock >= 0)
|
||||
do_lock = 1;
|
||||
|
@ -391,6 +394,8 @@ int main(int argc, char *argv[])
|
|||
res = state_daemon_kill(pidfile, cardname);
|
||||
} else if (!strcmp(cmd, "monitor")) {
|
||||
res = monitor(cardname);
|
||||
} else if (!strcmp(cmd, "clean")) {
|
||||
res = clean(cardname, extra_args);
|
||||
} else {
|
||||
fprintf(stderr, "alsactl: Unknown command '%s'...\n", cmd);
|
||||
res = -ENODEV;
|
||||
|
|
|
@ -40,6 +40,7 @@ int monitor(const char *name);
|
|||
int state_daemon(const char *file, const char *cardname, int period,
|
||||
const char *pidfile);
|
||||
int state_daemon_kill(const char *pidfile, const char *cmd);
|
||||
int clean(const char *cardname, char *const *extra_args);
|
||||
|
||||
/* utils */
|
||||
|
||||
|
|
228
alsactl/clean.c
Normal file
228
alsactl/clean.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* Advanced Linux Sound Architecture Control Program
|
||||
* Copyright (c) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 clean_one_control(snd_ctl_t *handle, snd_ctl_elem_id_t *elem_id,
|
||||
snd_ctl_elem_id_t **filter)
|
||||
{
|
||||
snd_ctl_elem_info_t *info;
|
||||
char *s;
|
||||
int err;
|
||||
|
||||
snd_ctl_elem_info_alloca(&info);
|
||||
snd_ctl_elem_info_set_id(info, elem_id);
|
||||
err = snd_ctl_elem_info(handle, info);
|
||||
if (err < 0) {
|
||||
s = snd_ctl_ascii_elem_id_get(elem_id);
|
||||
error("Cannot read control info '%s': %s", s, snd_strerror(err));
|
||||
free(s);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (!snd_ctl_elem_info_is_user(info))
|
||||
return 0;
|
||||
|
||||
s = snd_ctl_ascii_elem_id_get(elem_id);
|
||||
dbg("Application control \"%s\" found.", s);
|
||||
if (filter) {
|
||||
for (; *filter; filter++) {
|
||||
if (snd_ctl_elem_id_compare(elem_id, *filter) == 0)
|
||||
break;
|
||||
}
|
||||
if (*filter == NULL) {
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
err = snd_ctl_elem_remove(handle, elem_id);
|
||||
if (err < 0) {
|
||||
error("Cannot remove control '%s': %s", s, snd_strerror(err));
|
||||
free(s);
|
||||
return err;
|
||||
}
|
||||
dbg("Application control \"%s\" removed.", s);
|
||||
free(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void filter_controls_free(snd_ctl_elem_id_t **_filter)
|
||||
{
|
||||
snd_ctl_elem_id_t **filter;
|
||||
|
||||
for (filter = _filter; filter; filter++)
|
||||
free(*filter);
|
||||
free(_filter);
|
||||
}
|
||||
|
||||
static int filter_controls_parse(char *const *controls, snd_ctl_elem_id_t ***_filter)
|
||||
{
|
||||
snd_ctl_elem_id_t **filter = NULL;
|
||||
char *const *c;
|
||||
char *s;
|
||||
unsigned int count, idx;
|
||||
int err;
|
||||
|
||||
if (!controls)
|
||||
goto fin;
|
||||
for (count = 0, c = controls; *c; c++, count++);
|
||||
if (count == 0)
|
||||
goto fin;
|
||||
filter = calloc(count + 1, sizeof(snd_ctl_elem_id_t *));
|
||||
if (filter == NULL) {
|
||||
nomem:
|
||||
error("No enough memory...");
|
||||
return -ENOMEM;
|
||||
}
|
||||
filter[count] = NULL;
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
err = snd_ctl_elem_id_malloc(&filter[idx]);
|
||||
if (err < 0) {
|
||||
filter_controls_free(filter);
|
||||
goto nomem;
|
||||
}
|
||||
err = snd_ctl_ascii_elem_id_parse(filter[idx], controls[idx]);
|
||||
if (err < 0) {
|
||||
error("Cannot parse id '%s': %s", controls[idx], snd_strerror(err));
|
||||
filter_controls_free(filter);
|
||||
return err;
|
||||
}
|
||||
s = snd_ctl_ascii_elem_id_get(filter[idx]);
|
||||
dbg("Add to filter: \"%s\"", s);
|
||||
free(s);
|
||||
}
|
||||
fin:
|
||||
*_filter = filter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int clean_controls(int cardno, char *const *controls)
|
||||
{
|
||||
snd_ctl_t *handle;
|
||||
snd_ctl_elem_list_t *list;
|
||||
snd_ctl_elem_id_t *elem_id;
|
||||
snd_ctl_elem_id_t **filter;
|
||||
char name[32];
|
||||
unsigned int idx, count;
|
||||
int err;
|
||||
|
||||
snd_ctl_elem_id_alloca(&elem_id);
|
||||
snd_ctl_elem_list_alloca(&list);
|
||||
|
||||
err = filter_controls_parse(controls, &filter);
|
||||
if (err < 0)
|
||||
return 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));
|
||||
filter_controls_free(filter);
|
||||
return err;
|
||||
}
|
||||
dbg("Control device '%s' opened.", name);
|
||||
err = snd_ctl_elem_list(handle, list);
|
||||
if (err < 0) {
|
||||
error("Cannot determine controls: %s", snd_strerror(err));
|
||||
goto fin_err;
|
||||
}
|
||||
count = snd_ctl_elem_list_get_count(list);
|
||||
if (count == 0)
|
||||
goto fin_ok;
|
||||
snd_ctl_elem_list_set_offset(list, 0);
|
||||
if ((err = snd_ctl_elem_list_alloc_space(list, count)) < 0) {
|
||||
error("No enough memory...");
|
||||
goto fin_err;
|
||||
}
|
||||
if ((err = snd_ctl_elem_list(handle, list)) < 0) {
|
||||
error("Cannot determine controls (2): %s", snd_strerror(err));
|
||||
goto fin_err;
|
||||
}
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
snd_ctl_elem_list_get_id(list, idx, elem_id);
|
||||
err = clean_one_control(handle, elem_id, filter);
|
||||
if (err < 0)
|
||||
goto fin_err;
|
||||
}
|
||||
fin_ok:
|
||||
filter_controls_free(filter);
|
||||
snd_ctl_close(handle);
|
||||
return 0;
|
||||
fin_err:
|
||||
filter_controls_free(filter);
|
||||
snd_ctl_close(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
int clean(const char *cardname, char *const *extra_args)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!cardname) {
|
||||
int card, first = 1;
|
||||
|
||||
card = -1;
|
||||
/* find each installed soundcards */
|
||||
while (1) {
|
||||
if (snd_card_next(&card) < 0)
|
||||
break;
|
||||
if (card < 0) {
|
||||
if (first) {
|
||||
if (ignore_nocards) {
|
||||
err = 0;
|
||||
goto out;
|
||||
} else {
|
||||
error("No soundcards found...");
|
||||
err = -ENODEV;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
first = 0;
|
||||
if ((err = clean_controls(card, extra_args)))
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
int cardno;
|
||||
|
||||
cardno = snd_card_get_index(cardname);
|
||||
if (cardno < 0) {
|
||||
error("Cannot find soundcard '%s'...", cardname);
|
||||
err = cardno;
|
||||
goto out;
|
||||
}
|
||||
if ((err = clean_controls(cardno, extra_args))) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
}
|
|
@ -19,7 +19,7 @@ AC_PROG_MKDIR_P
|
|||
AC_PROG_LN_S
|
||||
AC_PROG_SED
|
||||
PKG_PROG_PKG_CONFIG
|
||||
AM_PATH_ALSA(1.0.27)
|
||||
AM_PATH_ALSA(1.2.5)
|
||||
if test "x$enable_alsatest" = "xyes"; then
|
||||
AC_CHECK_FUNC([snd_ctl_elem_add_enumerated],
|
||||
, [AC_ERROR([No user enum control support in alsa-lib])])
|
||||
|
|
Loading…
Reference in a new issue