From fb4cba436c691ebadb24068977643674fb8c143e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 8 Jan 2005 21:36:53 +0000 Subject: * add new module for LIRC volume control git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@333 fefdeb5f-60dc-0310-8127-8f9354f1896f --- configure.ac | 7 ++ polyp/Makefile.am | 20 ++++- polyp/module-lirc.c | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++ polyp/module-match.c | 6 +- polyp/module-oss.c | 1 - 5 files changed, 248 insertions(+), 7 deletions(-) create mode 100644 polyp/module-lirc.c diff --git a/configure.ac b/configure.ac index e287f279..644c4050 100644 --- a/configure.ac +++ b/configure.ac @@ -167,6 +167,13 @@ AC_MSG_RESULT(yes)], AC_SUBST(LIBWRAP_LIBS) LIBS="$saved_LIBS" +HAVE_LIRC=1 +AC_CHECK_HEADER(lirc/lirc_client.h,[AC_CHECK_LIB(lirc_client,lirc_init,,HAVE_LIRC=0)],HAVE_LIRC=0) +LIRC_LIBS=-llirc_client +AC_SUBST(LIRC_CFLAGS) +AC_SUBST(LIRC_LIBS) +AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1]) + # If using GCC specify some additional parameters if test "x$GCC" = "xyes" ; then CFLAGS="$CFLAGS -pipe -W -Wall -pedantic" diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 352e6a7a..95a80ec1 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -159,7 +159,8 @@ SYMDEF_FILES= \ module-tunnel-source-symdef.h \ module-null-sink-symdef.h \ module-esound-sink-symdef.h \ - module-zeroconf-publish-symdef.h + module-zeroconf-publish-symdef.h \ + module-lirc-symdef.h EXTRA_DIST+=$(SYMDEF_FILES) BUILT_SOURCES+=$(SYMDEF_FILES) @@ -242,7 +243,8 @@ libsocket_server_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la $(LI libsocket_client_la_SOURCES = socket-client.c socket-client.h libsocket_client_la_LDFLAGS = -avoid-version -libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la +libsocket_client_la_LIBADD = $(AM_LIBADD) libiochannel.la libsocket-util.la libparseaddr.la $(LIBASYNCNS_LIBS) +libsocket_client_la_CFLAGS = $(AM_CFLAGS) $(LIBASYNCNS_CFLAGS) libparseaddr_la_SOURCES = parseaddr.c parseaddr.h libparseaddr_la_LDFLAGS = -avoid-version @@ -691,6 +693,20 @@ mainloop_test_glib12_LDADD = $(mainloop_test_LDADD) $(GLIB12_LIBS) libpolyp-main endif +### LIRC support + +if HAVE_LIRC + +modlib_LTLIBRARIES+= \ + module-lirc.la + +module_lirc_la_SOURCES = module-lirc.c +module_lirc_la_LDFLAGS = -module -avoid-version +module_lirc_la_LIBADD = $(AM_LIBADD) $(LIRC_LIBS) +module_lirc_la_CFLAGS = $(AM_CFLAGS) $(LIRC_CFLAGS) + +endif + ### libpolypcore (needs to be updated) if BUILD_LIBPOLYPCORE diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c new file mode 100644 index 00000000..a68b5b99 --- /dev/null +++ b/polyp/module-lirc.c @@ -0,0 +1,221 @@ +/* $Id$ */ + +/*** + This file is part of polypaudio. + + polypaudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2 of the License, + or (at your option) any later version. + + polypaudio 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 Lesser General Public License + along with polypaudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "module.h" +#include "iochannel.h" +#include "log.h" +#include "module-lirc-symdef.h" +#include "namereg.h" +#include "sink.h" +#include "xmalloc.h" +#include "modargs.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("LIRC volume control") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("config= sink=") + +static const char* const valid_modargs[] = { + "config", + "sink", + NULL, +}; + +struct userdata { + int lirc_fd; + struct pa_io_event *io; + struct lirc_config *config; + char *sink_name; + struct pa_module *module; + float mute_toggle_save; +}; + +static int lirc_in_use = 0; + +static void io_callback(struct pa_mainloop_api *io, struct pa_io_event *e, int fd, enum pa_io_event_flags events, void*userdata) { + struct userdata *u = userdata; + char *name = NULL, *code = NULL; + assert(io); + assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log(__FILE__": lost connection to LIRC daemon.\n"); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + char *c; + + if (lirc_nextcode(&code) != 0 || !code) { + pa_log(__FILE__": lirc_nextcode() failed.\n"); + goto fail; + } + + c = pa_xstrdup(code); + c[strcspn(c, "\n\r")] = 0; + pa_log_debug(__FILE__": raw IR code '%s'\n", c); + pa_xfree(c); + + while (lirc_code2char(u->config, code, &name) == 0 && name) { + enum { INVALID, UP, DOWN, MUTE, RESET, MUTE_TOGGLE } volchange = INVALID; + + pa_log_info(__FILE__": translated IR code '%s'\n", name); + + if (strcasecmp(name, "volume-up") == 0) + volchange = UP; + else if (strcasecmp(name, "volume-down") == 0) + volchange = DOWN; + else if (strcasecmp(name, "mute") == 0) + volchange = MUTE; + else if (strcasecmp(name, "mute-toggle") == 0) + volchange = MUTE_TOGGLE; + else if (strcasecmp(name, "reset") == 0) + volchange = RESET; + + if (volchange == INVALID) + pa_log_warn(__FILE__": recieved unknown IR code '%s'\n", name); + else { + struct pa_sink *s; + + if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) + pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); + else { + double v = pa_volume_to_user(s->volume); + + switch (volchange) { + case UP: v += .05; break; + case DOWN: v -= .05; break; + case MUTE: v = 0; break; + case RESET: v = 1; break; + case MUTE_TOGGLE: { + + if (v > 0) { + u->mute_toggle_save = v; + v = 0; + } else + v = u->mute_toggle_save; + } + default: + ; + } + + pa_sink_set_volume(s, pa_volume_from_user(v)); + } + } + } + } + + free(code); + + return; + +fail: + u->module->core->mainloop->io_free(u->io); + u->io = NULL; + + pa_module_unload_request(u->module); + + free(code); +} + +int pa__init(struct pa_core *c, struct pa_module*m) { + struct pa_modargs *ma = NULL; + struct userdata *u; + assert(c && m); + + if (lirc_in_use) { + pa_log(__FILE__": module-lirc may no be loaded twice.\n"); + return -1; + } + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log(__FILE__": Failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = pa_xmalloc(sizeof(struct userdata)); + u->module = m; + u->io = NULL; + u->config = NULL; + u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL)); + u->lirc_fd = -1; + u->mute_toggle_save = 0; + + if ((u->lirc_fd = lirc_init("polypaudio", 1)) < 0) { + pa_log(__FILE__": lirc_init() failed.\n"); + goto fail; + } + + if (lirc_readconfig((char*) pa_modargs_get_value(ma, "config", NULL), &u->config, NULL) < 0) { + pa_log(__FILE__": lirc_readconfig() failed.\n"); + goto fail; + } + + u->io = c->mainloop->io_new(c->mainloop, u->lirc_fd, PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, io_callback, u); + + lirc_in_use = 1; + + pa_modargs_free(ma); + + return 0; + +fail: + + if (ma) + pa_modargs_free(ma); + + pa__done(c, m); + return -1; +} + +void pa__done(struct pa_core *c, struct pa_module*m) { + struct userdata *u; + assert(c); + assert(m); + + if (!(u = m->userdata)) + return; + + if (u->io) + m->core->mainloop->io_free(u->io); + + if (u->config) + lirc_freeconfig(u->config); + + if (u->lirc_fd >= 0) + lirc_deinit(); + + pa_xfree(u->sink_name); + pa_xfree(u); + + lirc_in_use = 0; +} diff --git a/polyp/module-match.c b/polyp/module-match.c index 9d969b31..3599a830 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -179,12 +179,10 @@ static void callback(struct pa_core *c, enum pa_subscription_event_type t, uint3 int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; - const char *table_file; struct userdata *u; assert(c && m); - if (!(ma = pa_modargs_new(m->argument, valid_modargs)) || - !(table_file = pa_modargs_get_value(ma, "table", NULL))) { + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log(__FILE__": Failed to parse module arguments\n"); goto fail; } @@ -194,7 +192,7 @@ int pa__init(struct pa_core *c, struct pa_module*m) { u->subscription = NULL; m->userdata = u; - if (load_rules(u, table_file) < 0) + if (load_rules(u, pa_modargs_get_value(ma, "table", NULL)) < 0) goto fail; u->subscription = pa_subscription_new(c, PA_SUBSCRIPTION_MASK_SINK_INPUT, callback, u); diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 67922d82..02acc6f4 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -295,7 +295,6 @@ int pa__init(struct pa_core *c, struct pa_module*m) { pa_log_info(__FILE__": device opened in %s mode.\n", mode == O_WRONLY ? "O_WRONLY" : (mode == O_RDONLY ? "O_RDONLY" : "O_RDWR")); - if (nfrags >= 2 && frag_size >= 1) if (pa_oss_set_fragments(fd, nfrags, frag_size) < 0) goto fail; -- cgit