[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