[alsa-devel] [PATCH - amixer] listen to D-Bus for volume-up, volume-down and mute signals.
Łukasz Stelmach
stlman at poczta.fm
Mon Aug 3 12:43:21 CEST 2009
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>
---
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