[pulseaudio-discuss] [PATCH 1/6] alsa: add jack detection support

Margarita Olaya magi at slimlogic.co.uk
Tue Apr 5 13:34:08 PDT 2011


This patch adds support for reading the status of sound card jack input
devices (i.e. jack insertion/removal detection).

A new module is created in order to monitor the status of sound card
jack insertion and removal events. It does this by creating a thread
that blocks on reading the sound card input event device and then firing
a hook that reports the jack status change.

Signed-off-by: Margarita Olaya Cabrera <magi at slimlogic.co.uk>
---
 src/Makefile.am                            |    9 +-
 src/modules/alsa/module-alsa-jack-detect.c |  204 ++++++++++++++++++++++++++++
 src/pulsecore/core.h                       |    2 +
 src/pulsecore/jack-detect.h                |   42 ++++++
 4 files changed, 256 insertions(+), 1 deletions(-)
 create mode 100644 src/modules/alsa/module-alsa-jack-detect.c
 create mode 100644 src/pulsecore/jack-detect.h

diff --git a/src/Makefile.am b/src/Makefile.am
index dc2a1cd..b475350 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1114,7 +1114,8 @@ modlibexec_LTLIBRARIES += \
 		libalsa-util.la \
 		module-alsa-sink.la \
 		module-alsa-source.la \
-		module-alsa-card.la
+		module-alsa-card.la \
+		module-alsa-jack-detect.la

 dist_alsaprofilesets_DATA = \
 		modules/alsa/mixer/profile-sets/default.conf \
@@ -1303,6 +1304,7 @@ SYMDEF_FILES = \
 		module-alsa-sink-symdef.h \
 		module-alsa-source-symdef.h \
 		module-alsa-card-symdef.h \
+		modules/alsa/module-alsa-jack-detect-symdef.h\
 		module-coreaudio-detect-symdef.h \
 		module-coreaudio-device-symdef.h \
 		module-solaris-symdef.h \
@@ -1616,6 +1618,11 @@ module_alsa_card_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_alsa_card_la_LIBADD = $(MODULE_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la
 module_alsa_card_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)

+module_alsa_jack_detect_la_SOURCES = modules/alsa/module-alsa-jack-detect.c
+module_alsa_jack_detect_la_LDFLAGS = $(MODULE_LDFLAGS)
+module_alsa_jack_detect_la_LIBADD = $(MODULE_LIBADD)
$(ASOUNDLIB_LIBS) libalsa-util.la
+module_alsa_jack_detect_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
+
 # Solaris

 module_solaris_la_SOURCES = modules/module-solaris.c
diff --git a/src/modules/alsa/module-alsa-jack-detect.c
b/src/modules/alsa/module-alsa-jack-detect.c
new file mode 100644
index 0000000..4635dc4
--- /dev/null
+++ b/src/modules/alsa/module-alsa-jack-detect.c
@@ -0,0 +1,204 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2011 Wolfson Microelectronics PLC
+ Author Margarita Olaya <magi at slimlogic.co.uk>
+
+ PulseAudio 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.1 of the License,
+ or (at your option) any later version.
+
+ PulseAudio 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 PulseAudio; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+
+ Jack detect integration was kindly sponsored by Wolfson Microelectronics PLC.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/jack-detect.h>
+#include <pulse/proplist.h>
+
+#include "alsa-util.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/input.h>
+#include <pthread.h>
+
+#include "module-alsa-jack-detect-symdef.h"
+
+PA_MODULE_AUTHOR("Margarita Olaya");
+PA_MODULE_DESCRIPTION("ALSA Jack Detect");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(FALSE);
+PA_MODULE_USAGE(
+    "device_id=<ALSA jack device> "
+    "card_name=<name for the card> ");
+
+static const char* const valid_modargs[] = {
+    "card_name",
+    "device_id",
+    NULL
+};
+
+#define DEFAULT_DEVICE_ID "0"
+
+struct userdata {
+    pa_core *core;
+    pa_module *module;
+
+    char *device_id;
+    int fd;
+
+    char *card_name;
+    pthread_t reader;
+};
+
+static void jack_report(struct userdata *u, struct input_event *event)
+{
+    pa_jack_detect_t jack;
+
+    jack.card = u->card_name;
+
+    pa_log_debug("card %s event type %x code %x value %x",
u->card_name, event->code, event->type, event->value);
+
+    /* only process switch events */
+    if (event->type != EV_SW) {
+        pa_log_debug("card %s ignored event type %x", u->card_name,
event->type);
+        return;
+    }
+
+    switch (event->code) {
+    case SW_HEADPHONE_INSERT:
+        jack.event = PA_JACK_HEADPHONES;
+        break;
+    case SW_MICROPHONE_INSERT:
+        jack.event = PA_JACK_MICROPHONE;
+        break;
+    case SW_LINEOUT_INSERT:
+        jack.event = PA_JACK_LINEOUT;
+        break;
+    case SW_JACK_PHYSICAL_INSERT:
+        jack.event = PA_JACK_UNKNOWN;
+        break;
+    default:
+        pa_log_debug("card %s ignored event code %x", u->card_name,
event->code);
+        break;
+    }
+
+    if (event->value)
+        pa_hook_fire(&u->core->hooks[PA_CORE_HOOK_JACK_INSERT], &jack);
+    else
+        pa_hook_fire(&u->core->hooks[PA_CORE_HOOK_JACK_REMOVE], &jack);
+}
+
+static void *jack_detect_thread(void *tdata)
+{
+    struct userdata *u = tdata;
+    struct input_event event;
+
+    pa_log_debug("jack thread started for card %s", u->card_name);
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+    pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+
+    while (read(u->fd, &event, sizeof(event)) == sizeof(event)) {
+       jack_report(u, &event);
+    }
+
+    pa_log_debug("jack thread stopped for card %s", u->card_name);
+    return NULL;
+}
+
+static void jack_get_initial_state(struct userdata *u)
+{
+    struct input_event event;
+    int err;
+
+    err = ioctl(u->fd, EVIOCGSW(sizeof(event)), &event);
+    if (err < 0) {
+        pa_log("Failed to read initial %s jack status %d", u->device_id, err);
+        return;
+    }
+
+    jack_report(u, &event);
+}
+
+int pa__init(pa_module *m) {
+    pa_modargs *ma;
+    struct userdata *u;
+    pa_alsa_refcnt_inc();
+    pa_assert(m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log("Failed to parse module arguments");
+        goto fail;
+    }
+
+    m->userdata = u = pa_xnew0(struct userdata, 1);
+    u->core = m->core;
+    u->module = m;
+    u->device_id = pa_xstrdup(pa_modargs_get_value(ma, "device_id",
DEFAULT_DEVICE_ID));
+    u->card_name = pa_xstrdup(pa_modargs_get_value(ma, "card_name",
DEFAULT_DEVICE_ID));
+    u->core = m->core;
+
+    /* open the input event device */
+    if ((u->fd = open(u->device_id, O_RDONLY)) < 0)
+        goto fail_jack;
+
+    /* read the initial jack state */
+    jack_get_initial_state(u);
+
+    /* start the jack reader thread */
+    pa_assert_se(pthread_create(&u->reader, NULL, jack_detect_thread, u) == 0);
+
+    return 0;
+
+fail_jack:
+    pa_xfree(u->device_id);
+    pa_xfree(u->card_name);
+    pa_xfree(u);
+
+fail:
+    if (ma)
+        pa_modargs_free(ma);
+
+    pa__done(m);
+    return -1;
+}
+
+void pa__done(pa_module *m) {
+    struct userdata *u;
+
+    pa_assert(m);
+
+    if (!(u = m->userdata))
+        goto finish;
+
+    /* wait for reader thread to finish */
+    pthread_cancel(u->reader);
+    pthread_join(u->reader, NULL);
+    close(u->fd);
+
+    pa_xfree(u->device_id);
+    pa_xfree(u->card_name);
+    pa_xfree(u);
+
+finish:
+    pa_alsa_refcnt_dec();
+}
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index 358b98d..830145a 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -114,6 +114,8 @@ typedef enum pa_core_hook {
     PA_CORE_HOOK_CARD_PUT,
     PA_CORE_HOOK_CARD_UNLINK,
     PA_CORE_HOOK_CARD_PROFILE_CHANGED,
+    PA_CORE_HOOK_JACK_INSERT,
+    PA_CORE_HOOK_JACK_REMOVE,
     PA_CORE_HOOK_MAX
 } pa_core_hook_t;

diff --git a/src/pulsecore/jack-detect.h b/src/pulsecore/jack-detect.h
new file mode 100644
index 0000000..4fc67c6
--- /dev/null
+++ b/src/pulsecore/jack-detect.h
@@ -0,0 +1,42 @@
+#ifndef foopulsejackdetecthfoo
+#define foopulsejackdetecthfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2011 Wolfson Microelectronics PLC
+  Author Margarita Olaya <magi at slimlogic.co.uk>
+
+  PulseAudio 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.1 of the License,
+  or (at your option) any later version.
+
+  PulseAudio 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 PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <inttypes.h>
+
+typedef enum pa_jack_event {
+    PA_JACK_HEADPHONES,
+    PA_JACK_HEADSET,
+    PA_JACK_MICROPHONE,
+    PA_JACK_LINEOUT,
+    PA_JACK_UNKNOWN,
+    PA_JACK_MAX
+} pa_jack_event_t;
+
+typedef struct pa_jack_detect {
+    pa_jack_event_t event;
+    char *card;
+} pa_jack_detect_t;
+
+#endif
-- 
1.7.1



More information about the pulseaudio-discuss mailing list