[alsa-devel] [PATCH - amixer] listen to D-Bus for volume-up, volume-down and mute signals.
Takashi Iwai
tiwai at suse.de
Mon Aug 3 12:51:56 CEST 2009
At Mon, 3 Aug 2009 12:43:21 +0200,
Łukasz Stelmach wrote:
>
>
> The patch introduces D-Bus support in amixer. With --dbus option given amixer
> works continiously (like with the --stdin) waiting for
> org.freedesktop.Hal.Device.Condition with the first argument "ButtonPressed"
> and the second being one of: "volume-up", "volume-down" and "mute". These
> are emmited by the HAL input helper. A single amixer process can controll
> one mixer item. There are options to choose a specific item to controll,
> an input device to listen and a single adjustment step size.
>
> Signed-off-by: Łukasz Stelmach <stlman at poczta.fm>
Thanks for the patch.
The approach is interesting, but I'm not sure whether we should put
all into amixer in this way since we don't want extra library
dependency. (Note: amixer could be used in initrd.)
I think it's better to split the code and make it as an individual
daemon instead of additional options of amixer.
Just my $0.02.
thanks,
Takashi
> ---
> amixer/Makefile.am | 3 +-
> amixer/amixer.1 | 18 ++++++
> amixer/amixer.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> configure.in | 12 ++++
> 4 files changed, 203 insertions(+), 1 deletions(-)
>
> diff --git a/amixer/Makefile.am b/amixer/Makefile.am
> index fcd0e81..fa951a6 100644
> --- a/amixer/Makefile.am
> +++ b/amixer/Makefile.am
> @@ -1,5 +1,6 @@
> INCLUDES = -I$(top_srcdir)/include
> -LDADD = -lm
> +LDADD = -lm @DBUS_LIBS@
> +CFLAGS += @DBUS_CFLAGS@
> # LDFLAGS = -static
> # CFLAGS += -g -Wall
>
> diff --git a/amixer/amixer.1 b/amixer/amixer.1
> index b1ac323..bc160be 100644
> --- a/amixer/amixer.1
> +++ b/amixer/amixer.1
> @@ -88,6 +88,24 @@ Select the card number to control. The device name created from this
> parameter has syntax 'hw:N' where N is specified card number.
>
> .TP
> +\fI\-\-dbus[=\fISCONTROL\fP]
> +
> +Connect to system D-Bus and wait for \fIorg.freedesktop.Hal.Device.Condition\fP
> +signals with ButtonPressed as the first argument and one of: \fIvolume-up\fP,
> +\fIvolume-down\fP or \fImute\fP as the second one. Control the selected
> +\fISCONTROL\fP item. The default item is 'Master,0'.
> +
> +.TP
> +\fI\-\-dbus-path=<\fIUDI\fP>
> +
> +Choose a particular input device that emits control events.
> +
> +.TP
> +\fI\-\-dbus-step=<\fIN\fP>
> +
> +Set an amount by wich to increase or decrease volume upon event.
> +
> +.TP
> \fI\-D\fP device
>
> Select the device name to control. The default control name is 'default'.
> diff --git a/amixer/amixer.c b/amixer/amixer.c
> index 9620721..31de674 100644
> --- a/amixer/amixer.c
> +++ b/amixer/amixer.c
> @@ -18,6 +18,8 @@
> *
> */
>
> +#include "aconfig.h"
> +
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> @@ -31,6 +33,10 @@
> #include <sys/poll.h>
> #include "amixer.h"
>
> +#ifdef HAVE_DBUS
> +#include <dbus/dbus.h>
> +#endif /* HAVE_DBUS */
> +
> #define LEVEL_BASIC (1<<0)
> #define LEVEL_INACTIVE (1<<1)
> #define LEVEL_ID (1<<2)
> @@ -43,6 +49,12 @@ static int ignore_error = 0;
> static struct snd_mixer_selem_regopt smixer_options;
> static char card[64] = "default";
>
> +#ifdef HAVE_DBUS
> +static char dbus_sctl[64] = "Master,0";
> +static char *dbus_path = NULL;
> +static char dbus_step[8] = "1";
> +#endif /* HAVE_DBUS */
> +
> static void error(const char *fmt,...)
> {
> va_list va;
> @@ -60,6 +72,11 @@ static int help(void)
> printf("\nAvailable options:\n");
> printf(" -h,--help this help\n");
> printf(" -c,--card N select the card\n");
> +#ifdef HAVE_DBUS
> + printf(" --dbus[=sID] Connect to the system D-Bus and wait for volume messages\n");
> + printf(" --dbus-path UDI Choose a particular input device (udi)\n");
> + printf(" --dbus-step N Set the step size (default: 1)\n");
> +#endif /* HAVE_DBUS */
> printf(" -D,--device N select the device, default '%s'\n", card);
> printf(" -d,--debug debug mode\n");
> printf(" -n,--nocheck do not perform range checking\n");
> @@ -1887,15 +1904,147 @@ static int exec_stdin(void)
> return 0;
> }
>
> +#ifdef HAVE_DBUS
> +
> +#define OPT_DBUS 0x81
> +#define OPT_DBUS_PATH 0x82
> +#define OPT_DBUS_STEP 0x83
> +
> +void* get_dbus_arg(DBusMessageIter* args, int type, void** out) {
> + if (type != dbus_message_iter_get_arg_type(args))
> + return NULL;
> + dbus_message_iter_get_basic(args, out);
> + dbus_message_iter_next(args);
> + return *out;
> +}
> +
> +int exec_dbus(void)
> +{
> + char *sargv[MAX_ARGS];
> + int sargc;
> + const char* s;
> + int stepl;
> + DBusError error;
> + DBusMessage* msg;
> + DBusConnection *conn;
> + DBusMessageIter args;
> +
> + stepl = strlen(dbus_step);
> + dbus_step[stepl+1] = '\0';
> +
> + dbus_error_init (&error);
> + conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
> +
> + if(!conn) {
> + fprintf(stderr, "dbus:%s: %s\n",
> + error.name, error.message);
> + return 1;
> + }
> +
> + dbus_bus_add_match(conn,
> + "type='signal',"
> + "interface='org.freedesktop.Hal.Device',"
> + "member='Condition'",
> + &error);
> + /* The first message is a NameOwnerChanged signal, ignore it. */
> + msg = dbus_connection_pop_message(conn);
> + dbus_message_unref(msg);
> +
> + if(dbus_error_is_set(&error)) {
> + fprintf(stderr, "dbus:match error:%s\n",
> + error.message);
> + return 1;
> + }
> +
> + while (1) {
> + sargv[0] = dbus_sctl; sargc = 1;
> +
> + if (!(msg = dbus_connection_pop_message(conn))) {
> + dbus_connection_read_write(conn, -1);
> + continue;
> + }
> +
> + s = dbus_message_get_interface(msg);
> + if(strncmp("org.freedesktop.Hal.Device", s, 26)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:unsupported interface:%s\n", s);
> + goto badmessage;
> + }
> +
> + if(dbus_path &&
> + (s=dbus_message_get_path(msg)) &&
> + strncmp(dbus_path, s, strlen(s))) {
> + if(debugflag)
> + fprintf(stderr, "dbus:not the selected udi:%s\n", s);
> + goto badmessage;
> + }
> +
> + if(!dbus_message_iter_init(msg, &args)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:message has no arguments\n");
> + goto badmessage;
> + }
> +
> + if (strncmp(get_dbus_arg(&args, DBUS_TYPE_STRING, (void*)&s), "ButtonPressed", 13)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:not a ButtonPressed event\n");
> + goto badmessage;
> + }
> +
> + if (!get_dbus_arg(&args, DBUS_TYPE_STRING, (void*)&s)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:invalid argument type\n");
> + goto badmessage;
> + }
> +
> + /* static int sset(unsigned int argc, char *argv[], int roflag, int keep_handle) */
> + if (!strncmp(s, "volume-up", 9)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:volume-up\n");
> + dbus_step[stepl]='+';
> + sargv[1] = dbus_step;
> + } else if (!strncmp(s, "volume-down", 11)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:volume-down\n");
> + dbus_step[stepl]='-';
> + sargv[1] = dbus_step;
> + } else if (!strncmp(s, "mute", 4)) {
> + if(debugflag)
> + fprintf(stderr, "dbus:mute (toggle)\n");
> + sargv[1] = "toggle";
> + } else {
> + if(debugflag)
> + fprintf(stderr, "dbus:invalid argument value\n");
> + goto badmessage;
> + }
> + sset(++sargc, sargv, 0, 1);
> +badmessage:
> + dbus_message_unref(msg);
> + }
> +
> + if(conn)
> + dbus_connection_unref(conn);
> + return 0;
> +}
> +#endif /* HAVE_DBUS */
>
> int main(int argc, char *argv[])
> {
> int morehelp, level = 0;
> int read_stdin = 0;
> +#ifdef HAVE_DBUS
> + int read_dbus = 0;
> + int t;
> +#endif /* HAVE_DBUS */
> static const struct option long_option[] =
> {
> {"help", 0, NULL, 'h'},
> {"card", 1, NULL, 'c'},
> +#ifdef HAVE_DBUS
> + {"dbus", optional_argument, NULL, OPT_DBUS},
> + {"dbus-path", 1, NULL, OPT_DBUS_PATH},
> + {"dbus-step", 1, NULL, OPT_DBUS_STEP},
> +#endif /* HAVE_DBUS */
> {"device", 1, NULL, 'D'},
> {"quiet", 0, NULL, 'q'},
> {"inactive", 0, NULL, 'i'},
> @@ -1964,6 +2113,24 @@ int main(int argc, char *argv[])
> case 's':
> read_stdin = 1;
> break;
> +#ifdef HAVE_DBUS
> + case OPT_DBUS:
> + if(optarg) {
> + strncpy(dbus_sctl, optarg, sizeof(dbus_sctl)-1);
> + dbus_sctl[sizeof(dbus_sctl)-1] = '\0';
> + }
> + read_dbus = 1;
> + break;
> + case OPT_DBUS_PATH:
> + dbus_path=optarg;
> + break;
> + case OPT_DBUS_STEP:
> + t=atoi(optarg);
> + if(t > 0 && t <= 999999) {
> + snprintf(dbus_step, sizeof(dbus_step), "%d", atoi(optarg));
> + }
> + break;
> +#endif /* HAVE_DBUS */
> default:
> fprintf(stderr, "Invalid switch or option needs an argument.\n");
> morehelp++;
> @@ -1978,6 +2145,10 @@ int main(int argc, char *argv[])
> if (read_stdin)
> return exec_stdin();
>
> +#ifdef HAVE_DBUS
> + if(read_dbus)
> + return exec_dbus();
> +#endif /* HAVE_DBUS */
> if (argc - optind <= 0) {
> return selems(LEVEL_BASIC | level) ? 1 : 0;
> }
> diff --git a/configure.in b/configure.in
> index 1349ff3..717d6c5 100644
> --- a/configure.in
> +++ b/configure.in
> @@ -7,6 +7,9 @@ AM_INIT_AUTOMAKE(alsa-utils, 1.0.20)
> AM_GNU_GETTEXT([external])
> AM_GNU_GETTEXT_VERSION([0.15])
>
> +dnl required versions of other packages
> +m4_define([dbus_required_version], [1.2.0])
> +
> dnl Checks for programs.
>
> dnl try to gues cross-compiler if not set
> @@ -74,6 +77,15 @@ AC_ARG_ENABLE(alsamixer,
> no) alsamixer=false ;;
> *) AC_MSG_ERROR(bad value ${enableval} for --enable-alsamixer) ;;
> esac],[alsamixer=true])
> +AC_ARG_WITH(dbus, [ --with-dbus Enable D-Bus support in amixer])
> + if test "x$with_dbus" != xno; then
> + PKG_CHECK_MODULES(DBUS, dbus-1 >= dbus_required_version,
> + have_dbus=yes,
> + have_dbus=no)
> + fi
> + if test "x$have_dbus" = xyes; then
> + AC_DEFINE(HAVE_DBUS, 1, [Define to 1 if amixer is to support D-Bus])
> + fi
> fi
> AM_CONDITIONAL(ALSAMIXER, test x$alsamixer = xtrue)
>
> --
> 1.6.3.3
>
>
> ----------------------------------------------------------------------
> Zostan Dziewczyna lub Chlopakiem lata!
> Wygraj skuter >> http://link.interia.pl/f22a7
>
More information about the Alsa-devel
mailing list