]> code.delx.au - pulseaudio/commitdiff
add simple hardware auto detection module
authorLennart Poettering <lennart@poettering.net>
Thu, 16 Feb 2006 01:17:30 +0000 (01:17 +0000)
committerLennart Poettering <lennart@poettering.net>
Thu, 16 Feb 2006 01:17:30 +0000 (01:17 +0000)
git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@486 fefdeb5f-60dc-0310-8127-8f9354f1896f

polyp/Makefile.am
polyp/module-detect.c [new file with mode: 0644]

index e2154b322299265b0ed223e0ce22b929cf760933..061b82b45e9d41153b8a89c034d949e414ce0353 100644 (file)
@@ -47,6 +47,7 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS
 AM_CFLAGS += $(LTDLINCL)
 AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
 AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\"
+#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\"
 AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\"
 AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\"
 
@@ -676,7 +677,8 @@ modlib_LTLIBRARIES += \
                module-null-sink.la \
                module-esound-sink.la \
                module-http-protocol-tcp.la \
-               module-http-protocol-tcp6.la
+               module-http-protocol-tcp6.la \
+               module-detect.la
 
 if HAVE_AF_UNIX
 modlib_LTLIBRARIES += \
@@ -788,7 +790,8 @@ SYMDEF_FILES = \
                module-alsa-sink-symdef.h \
                module-alsa-source-symdef.h \
                module-solaris-symdef.h \
-               module-waveout-symdef.h
+               module-waveout-symdef.h \
+               module-detect-symdef.h
 
 EXTRA_DIST += $(SYMDEF_FILES)
 BUILT_SOURCES += $(SYMDEF_FILES)
@@ -1009,6 +1012,12 @@ module_waveout_la_LDFLAGS = -module -avoid-version
 module_waveout_la_LIBADD = $(AM_LIBADD) libpolypcore.la -lwinmm
 module_waveout_la_CFLAGS = $(AM_CFLAGS)
 
+# Hardware autodetection module
+module_detect_la_SOURCES = module-detect.c
+module_detect_la_LDFLAGS = -module -avoid-version
+module_detect_la_LIBADD = $(AM_LIBADD)
+module_detect_la_CFLAGS = $(AM_CFLAGS)
+
 ###################################
 #        Some minor stuff         #
 ###################################
diff --git a/polyp/module-detect.c b/polyp/module-detect.c
new file mode 100644 (file)
index 0000000..ee75da3
--- /dev/null
@@ -0,0 +1,226 @@
+/* $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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "module.h"
+#include "log.h"
+#include "module-detect-symdef.h"
+#include "xmalloc.h"
+#include "modargs.h"
+
+PA_MODULE_AUTHOR("Lennart Poettering")
+PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers")
+PA_MODULE_VERSION(PACKAGE_VERSION)
+PA_MODULE_USAGE("just-one=<boolean>")
+
+static const char *endswith(const char *haystack, const char *needle) {
+    size_t l, m;
+    const char *p;
+    
+    if ((l = strlen(haystack)) < (m = strlen(needle)))
+        return NULL;
+
+    if (strcmp(p = haystack + l - m, needle))
+        return NULL;
+
+    return p;
+}
+
+#ifdef HAVE_ALSA
+static int detect_alsa(pa_core *c, int just_one) {
+    FILE *f;
+    int n = 0, n_sink = 0, n_source = 0;
+
+    if (!(f = fopen("/proc/asound/devices", "r"))) {
+
+        if (errno != ENOENT)
+            pa_log_error(__FILE__": open(\"/proc/asound/devices\") failed: %s\n", strerror(errno));
+        
+        return -1;
+    }
+
+    while (!feof(f)) {
+        char line[64], args[64];
+        unsigned device, subdevice;
+        int is_sink;
+    
+        if (!fgets(line, sizeof(line), f))
+            break;
+
+        line[strcspn(line, "\r\n")] = 0;
+
+        if (endswith(line, "digital audio playback"))
+            is_sink = 1;
+        else if (endswith(line, "digital audio capture"))
+            is_sink = 0;
+        else
+            continue;
+
+        if (just_one && is_sink && n_sink >= 1)
+            continue;
+        
+        if (just_one && !is_sink && n_source >= 1)
+            continue;
+
+        if (sscanf(line, " %*i: [%u- %u]: ", &device, &subdevice) != 2)
+            continue;
+
+        /* Only one sink per device */
+        if (subdevice != 0)
+            continue;
+
+        snprintf(args, sizeof(args), "device=hw:%u,0", device);
+        if (!pa_module_load(c, is_sink ? "module-alsa-sink" : "module-alsa-source", args))
+            continue;
+
+        n++;
+
+        if (is_sink)
+            n_sink++;
+        else
+            n_source++;
+    }
+
+    fclose(f);
+    
+    return n;
+}
+#endif
+
+#ifdef HAVE_OSS
+static int detect_oss(pa_core *c, int just_one) {
+    FILE *f;
+    int n = 0, b = 0;
+    
+    if (!(f = fopen("/dev/sndstat", "r")) &&
+        !(f = fopen("/proc/sndstat", "r")) &&
+        !(f = fopen("/proc/asound/oss/sndstat", "r"))) {
+
+        if (errno != ENOENT)
+            pa_log_error(__FILE__": failed to open OSS sndstat device: %s\n", strerror(errno));
+
+        return -1;
+    }
+
+    while (!feof(f)) {
+        char line[64], args[64];
+        unsigned device;
+    
+        if (!fgets(line, sizeof(line), f))
+            break;
+
+        line[strcspn(line, "\r\n")] = 0;
+
+        if (!b) {
+            b = strcmp(line, "Audio devices:") == 0;
+            continue;
+        }
+
+        if (line[0] == 0)
+            break;
+        
+        if (sscanf(line, "%u: ", &device) != 1)
+            continue;
+
+        if (device == 0)
+            snprintf(args, sizeof(args), "device=/dev/dsp");
+        else
+            snprintf(args, sizeof(args), "device=/dev/dsp%u", device);
+        
+        if (!pa_module_load(c, "module-oss", args))
+            continue;
+
+        n++;
+
+        if (just_one)
+            break;
+    }
+
+    fclose(f);
+    return n;
+}
+#endif
+
+int pa__init(pa_core *c, pa_module*m) {
+    int just_one = 0, n = 0;
+    pa_modargs *ma;
+
+    static const char* const valid_modargs[] = {
+        "just-one",
+        NULL
+    };
+    
+    assert(c);
+    assert(m);
+
+    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
+        pa_log(__FILE__": Failed to parse module arguments\n");
+        goto fail;
+    }
+    
+    if (pa_modargs_get_value_boolean(ma, "just-one", &just_one) < 0) {
+        pa_log(__FILE__": just_one= expects a boolean argument.\n");
+        goto fail;
+    }
+
+#if HAVE_ALSA
+    if ((n = detect_alsa(c, just_one)) <= 0) 
+#endif
+#if HAVE_OSS
+    if ((n = detect_oss(c, just_one)) <= 0)
+#endif
+    {
+        pa_log_warn(__FILE__": failed to detect any sound hardware.\n");
+        goto fail;
+    }
+
+    pa_log_info(__FILE__": loaded %i modules.\n", n);
+    
+    /* We were successful and can unload ourselves now. */
+    pa_module_unload_request(m);
+
+    pa_modargs_free(ma);
+
+    return 0;
+
+fail:
+    if (ma)
+        pa_modargs_free(ma);
+    
+    return -1;
+}
+
+
+void pa__done(pa_core *c, pa_module*m) {
+    /* NOP */
+}
+