[pulseaudio-discuss] [RFC][PATCH] CoreAudio: add device detection module

Daniel Mack daniel at caiaq.de
Tue Nov 3 05:40:25 PST 2009


This is for RFC. Don't know if it makes sense to commit it already as
the module it instantiates is not yet finished. Anyway, let me know what
you think.

Daniel

>From a7a3f3a64859833cfcfc7877aba354d7d298f8e9 Mon Sep 17 00:00:00 2001
From: Daniel Mack <daniel at caiaq.de>
Subject: [PATCH] CoreAudio: add device detection module

This adds a new module for CoreAudio device detection. It registers a
callback to detect hotplugged devices and creates/destroys modules named
'module-coreaudio-device'. Devices are identified via a system-wide
unique AudioDeviceID.
---
 src/Makefile.am                                 |   19 ++
 src/modules/coreaudio/module-coreaudio-detect.c |  208 +++++++++++++++++++++++
 2 files changed, 227 insertions(+), 0 deletions(-)
 create mode 100644 src/modules/coreaudio/module-coreaudio-detect.c

diff --git a/src/Makefile.am b/src/Makefile.am
index e228800..eafc4ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1088,6 +1088,12 @@ modlibexec_LTLIBRARIES += \
 		module-oss.la
 endif
 
+if HAVE_COREAUDIO
+modlibexec_LTLIBRARIES += \
+		libcoreaudio-util.la \
+		module-coreaudio-detect.la
+endif
+
 pulselibexec_PROGRAMS =
 
 if HAVE_ALSA
@@ -1257,6 +1263,7 @@ SYMDEF_FILES = \
 		modules/alsa/module-alsa-sink-symdef.h \
 		modules/alsa/module-alsa-source-symdef.h \
 		modules/alsa/module-alsa-card-symdef.h \
+		modules/coreaudio/module-coreaudio-detect-symdef.h \
 		modules/module-solaris-symdef.h \
 		modules/module-waveout-symdef.h \
 		modules/module-detect-symdef.h \
@@ -1488,6 +1495,18 @@ module_oss_la_SOURCES = modules/oss/module-oss.c
 module_oss_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_oss_la_LIBADD = $(AM_LIBADD) liboss-util.la libpulsecore- at PA_MAJORMINORMICRO@.la libpulsecommon- at PA_MAJORMINORMICRO@.la libpulse.la
 
+# COREAUDIO
+
+libcoreaudio_util_la_SOURCES = modules/coreaudio/coreaudio-util.c modules/coreaudio/coreaudio-util.h
+libcoreaudio_util_la_LDFLAGS = -avoid-version
+libcoreaudio_util_la_LIBADD = libpulsecore- at PA_MAJORMINORMICRO@.la libpulsecommon- at PA_MAJORMINORMICRO@.la libpulse.la
+
+module_coreaudio_detect_la_SOURCES = modules/coreaudio/module-coreaudio-detect.c
+module_coreaudio_detect_la_LDFLAGS = $(MODULE_LDFLAGS) \
+			-Wl,-framework -Wl,Cocoa -framework CoreAudio \
+			-Wl,-framework -Wl,AudioUnit -framework AudioUnit
+module_coreaudio_detect_la_LIBADD = $(AM_LIBADD) libcoreaudio-util.la libpulsecore- at PA_MAJORMINORMICRO@.la libpulsecommon- at PA_MAJORMINORMICRO@.la libpulse.la
+
 # ALSA
 
 libalsa_util_la_SOURCES = modules/alsa/alsa-util.c modules/alsa/alsa-util.h modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h modules/alsa/alsa-source.c modules/alsa/alsa-source.h modules/reserve-wrap.c modules/reserve-wrap.h
diff --git a/src/modules/coreaudio/module-coreaudio-detect.c b/src/modules/coreaudio/module-coreaudio-detect.c
new file mode 100644
index 0000000..34d00fa
--- /dev/null
+++ b/src/modules/coreaudio/module-coreaudio-detect.c
@@ -0,0 +1,208 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2009 Daniel Mack <daniel at caiaq.de>
+
+  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.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+
+#include <pulsecore/module.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/log.h>
+#include <pulsecore/llist.h>
+
+#include <CoreAudio/CoreAudio.h>
+
+#include "module-coreaudio-detect-symdef.h"
+
+#define DEVICE_MODULE_NAME "module-coreaudio-device"
+
+PA_MODULE_AUTHOR("Daniel Mack");
+PA_MODULE_DESCRIPTION("CoreAudio device detection");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(TRUE);
+PA_MODULE_USAGE("");
+
+typedef struct ca_device ca_device;
+
+struct ca_device {
+    AudioDeviceID id;
+    unsigned int  module_index;
+    PA_LLIST_FIELDS(ca_device);
+};
+
+struct userdata {
+    PA_LLIST_HEAD(ca_device, devices);
+};
+
+static int ca_device_added(struct pa_module *m, AudioDeviceID id) {
+    char args[32];
+    pa_module *mod;
+    struct userdata *u = m->userdata;
+    struct ca_device *dev;
+
+    pa_assert(u);
+
+    pa_snprintf(args, sizeof(args), "device_id=%d", id);
+
+    pa_log_debug("Loading %s with arguments '%s'", DEVICE_MODULE_NAME, args);
+    mod = pa_module_load(m->core, DEVICE_MODULE_NAME, args);
+
+    if (!mod) {
+        pa_log_info("Failed to load module %s with arguments '%s'", DEVICE_MODULE_NAME, args);
+        return -1;
+    }
+
+    dev = pa_xnew0(ca_device, 1);
+    pa_assert(dev);
+
+    dev->module_index = mod->index;
+    dev->id = id;
+
+    PA_LLIST_INIT(ca_device, dev);
+    PA_LLIST_PREPEND(ca_device, u->devices, dev);
+
+    return 0;
+}
+
+static int ca_update_device_list(struct pa_module *m) {
+    OSStatus err;
+    UInt32 i, size, num_devices;
+    Boolean writable;
+    AudioDeviceID *device_id;
+    struct ca_device *dev;
+    struct userdata *u = m->userdata;
+
+    pa_assert(u);
+
+    /* get the number of currently available audio devices */
+    err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &size, &writable);
+    if (err) {
+        pa_log("Unable to get info for kAudioHardwarePropertyDevices.");
+        return -1;
+    }
+
+    num_devices = size / sizeof(AudioDeviceID);
+    device_id = pa_xnew(AudioDeviceID, num_devices);
+    pa_assert(device_id);
+
+    err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &size, device_id);
+    if (err) {
+        pa_log("Unable to get kAudioHardwarePropertyDevices.");
+        pa_xfree(device_id);
+        return -1;
+    }
+
+    /* scan for devices which are reported but not in our cached list */
+    for (i = 0; i < num_devices; i++) {
+        bool found = FALSE;
+
+        PA_LLIST_FOREACH(dev, u->devices)
+            if (dev->id == device_id[i]) {
+                found = TRUE;
+                break;
+            }
+
+        if (!found)
+            ca_device_added(m, device_id[i]);
+    }
+
+    /* scan for devices which are in our cached list but are not reported */
+scan_removed:
+
+    PA_LLIST_FOREACH(dev, u->devices) {
+        bool found = FALSE;
+
+        for (i = 0; i < num_devices; i++)
+            if (dev->id == device_id[i]) {
+                found = TRUE;
+                break;
+            }
+
+        if (!found) {
+            pa_log_debug("device id %d has been removed (module index %d)  %p", (unsigned int) dev->id, dev->module_index, dev);
+            pa_module_unload_request_by_index(m->core, dev->module_index, TRUE);
+            PA_LLIST_REMOVE(ca_device, u->devices, dev);
+            pa_xfree(dev);
+            /* the current list item pointer is not valid anymore, so start over. */
+            goto scan_removed;
+        }
+    }
+
+    pa_xfree(device_id);
+    return 0;
+}
+
+static OSStatus property_listener_proc(AudioHardwarePropertyID property, void *data) {
+    pa_module *m = data;
+
+    pa_assert(m);
+
+    if (property == kAudioHardwarePropertyDevices)
+        ca_update_device_list(m);
+
+    return 0;
+}
+
+int pa__init(pa_module *m) {
+    struct userdata *u = pa_xnew0(struct userdata, 1);
+
+    pa_assert(u);
+
+    PA_LLIST_HEAD_INIT(ca_device, u->devices);
+    m->userdata = u;
+
+    if (AudioHardwareAddPropertyListener(kAudioHardwarePropertyDevices, property_listener_proc, m)) {
+        pa_log("AudioHardwareAddPropertyListener() failed.");
+        goto fail;
+    }
+
+    if (ca_update_device_list(m))
+       goto fail;
+
+    return 0;
+
+fail:
+    pa_xfree(u);
+    return -1;
+}
+
+void pa__done(pa_module *m) {
+    struct userdata *u = m->userdata;
+    struct ca_device *dev = u->devices;
+
+    pa_assert(u);
+
+    AudioHardwareRemovePropertyListener(kAudioHardwarePropertyDevices, property_listener_proc);
+
+    while (dev) {
+        struct ca_device *next = dev->next;
+
+        pa_module_unload_request_by_index(m->core, dev->module_index, TRUE);
+        pa_xfree(dev);
+
+        dev = next;
+    }
+
+    pa_xfree(u);
+}
-- 
1.6.3.3




More information about the pulseaudio-discuss mailing list