]> code.delx.au - pulseaudio/blobdiff - src/modules/module-hal-detect.c
Merge remote branch 'origin/master-tx'
[pulseaudio] / src / modules / module-hal-detect.c
index fe601100ff66066c28d7a25c1af6c4d4dde2dab2..185191318cb757751360d468bdf91b9ff8b9bc32 100644 (file)
 #include <pulsecore/namereg.h>
 #include <pulsecore/core-scache.h>
 #include <pulsecore/modargs.h>
+#include <pulsecore/dbus-shared.h>
 
 #include <hal/libhal.h>
 
-#include "dbus-util.h"
 #include "module-hal-detect-symdef.h"
 
 PA_MODULE_AUTHOR("Shahms King");
 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(TRUE);
-#if defined(HAVE_ALSA) && defined(HAVE_OSS)
+#if defined(HAVE_ALSA) && defined(HAVE_OSS_OUTPUT)
 PA_MODULE_USAGE("api=<alsa or oss> "
-                "tsched=<enable system timer based scheduling mode?>");
+                "tsched=<enable system timer based scheduling mode?>"
+                "subdevices=<init all subdevices>");
 #elif defined(HAVE_ALSA)
 PA_MODULE_USAGE("api=<alsa> "
                 "tsched=<enable system timer based scheduling mode?>");
-#elif defined(HAVE_OSS)
-PA_MODULE_USAGE("api=<oss>");
+#elif defined(HAVE_OSS_OUTPUT)
+PA_MODULE_USAGE("api=<oss>"
+                "subdevices=<init all subdevices>");
 #endif
+PA_MODULE_DEPRECATED("Please use module-udev-detect instead of module-hal-detect!");
 
 struct device {
     char *udi, *originating_udi;
@@ -81,6 +84,9 @@ struct userdata {
 #ifdef HAVE_ALSA
     pa_bool_t use_tsched;
 #endif
+#ifdef HAVE_OSS_OUTPUT
+    pa_bool_t init_subdevs;
+#endif
 };
 
 #define CAPABILITY_ALSA "alsa"
@@ -90,6 +96,9 @@ static const char* const valid_modargs[] = {
     "api",
 #ifdef HAVE_ALSA
     "tsched",
+#endif
+#ifdef HAVE_OSS_OUTPUT
+    "subdevices",
 #endif
     NULL
 };
@@ -121,6 +130,7 @@ static const char *strip_udi(const char *udi) {
 enum alsa_type {
     ALSA_TYPE_PLAYBACK,
     ALSA_TYPE_CAPTURE,
+    ALSA_TYPE_CONTROL,
     ALSA_TYPE_OTHER
 };
 
@@ -141,6 +151,8 @@ static enum alsa_type hal_alsa_device_get_type(LibHalContext *context, const cha
         t = ALSA_TYPE_PLAYBACK;
     else if (pa_streq(type, "capture"))
         t = ALSA_TYPE_CAPTURE;
+    else if (pa_streq(type, "control"))
+        t = ALSA_TYPE_CONTROL;
 
     libhal_free_string(type);
 
@@ -171,7 +183,8 @@ static pa_bool_t hal_alsa_device_is_modem(LibHalContext *context, const char *ud
 
 finish:
     if (dbus_error_is_set(&error)) {
-        pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message);
+        if (!dbus_error_has_name(&error, "org.freedesktop.Hal.NoSuchProperty"))
+            pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message);
         dbus_error_free(&error);
     }
 
@@ -193,10 +206,23 @@ static int hal_device_load_alsa(struct userdata *u, const char *udi, struct devi
 
     /* We only care for PCM devices */
     type = hal_alsa_device_get_type(u->context, udi);
-    if (type == ALSA_TYPE_OTHER)
+
+    /* For each ALSA card that appears the control device will be the
+     * last one to be created, this is considered part of the ALSA
+     * usperspace API. We rely on this and load our modules only when
+     * the control device is available assuming that *all* device
+     * nodes have been properly created and assigned the right ACLs at
+     * that time. Also see:
+     *
+     * http://mailman.alsa-project.org/pipermail/alsa-devel/2009-April/015958.html
+     *
+     * and the associated thread.*/
+
+    if (type != ALSA_TYPE_CONTROL)
         goto fail;
 
-    /* We don't care for modems */
+    /* We don't care for modems -- this is most likely not set for
+     * control devices, so kind of pointless here. */
     if (hal_alsa_device_is_modem(u->context, udi))
         goto fail;
 
@@ -215,7 +241,7 @@ static int hal_device_load_alsa(struct userdata *u, const char *udi, struct devi
         goto fail;
 
     card_name = pa_sprintf_malloc("alsa_card.%s", strip_udi(originating_udi));
-    args = pa_sprintf_malloc("device_id=%u name=%s card_name=%s tsched=%i", card, strip_udi(originating_udi), card_name, (int) u->use_tsched);
+    args = pa_sprintf_malloc("device_id=%u name=\"%s\" card_name=\"%s\" tsched=%i card_properties=\"module-hal-detect.discovered=1\"", card, strip_udi(originating_udi), card_name, (int) u->use_tsched);
 
     pa_log_debug("Loading module-alsa-card with arguments '%s'", args);
     m = pa_module_load(u->core, "module-alsa-card", args);
@@ -244,9 +270,9 @@ fail:
 
 #endif
 
-#ifdef HAVE_OSS
+#ifdef HAVE_OSS_OUTPUT
 
-static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi) {
+static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi, pa_bool_t init_subdevices) {
     char *class = NULL, *dev = NULL, *e;
     int device;
     pa_bool_t r = FALSE;
@@ -276,7 +302,7 @@ static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi)
 
     /* We only care for the main device */
     device = libhal_device_get_property_int(context, udi, "oss.device", &error);
-    if (dbus_error_is_set(&error) || device != 0)
+    if (dbus_error_is_set(&error) || (device != 0 && init_subdevices == FALSE))
         goto finish;
 
     r = TRUE;
@@ -306,7 +332,7 @@ static int hal_device_load_oss(struct userdata *u, const char *udi, struct devic
     pa_assert(d);
 
     /* We only care for OSS PCM devices */
-    if (!hal_oss_device_is_pcm(u->context, udi))
+    if (!hal_oss_device_is_pcm(u->context, udi, u->init_subdevs))
         goto fail;
 
     /* We store only one entry per card, hence we look for the originating device */
@@ -376,7 +402,7 @@ static struct device* hal_device_add(struct userdata *u, const char *udi) {
     if (pa_streq(u->capability, CAPABILITY_ALSA))
         r = hal_device_load_alsa(u, udi,  d);
 #endif
-#ifdef HAVE_OSS
+#ifdef HAVE_OSS_OUTPUT
     if (pa_streq(u->capability, CAPABILITY_OSS))
         r = hal_device_load_oss(u, udi, d);
 #endif
@@ -409,11 +435,10 @@ static int hal_device_add_all(struct userdata *u) {
         int i;
 
         for (i = 0; i < n; i++) {
-            struct device *d;
-
-            if ((d = hal_device_add(u, udis[i])))
+            if (hal_device_add(u, udis[i])) {
                 count++;
-            else
+                pa_log_debug("Loaded device %s", udis[i]);
+            } else
                 pa_log_debug("Not loaded device %s", udis[i]);
         }
     }
@@ -449,10 +474,13 @@ static void device_added_cb(LibHalContext *context, const char *udi) {
 
     if (!hal_device_add(u, udi))
         pa_log_debug("Not loaded device %s", udi);
+    else
+        pa_log_debug("Loaded device %s", udi);
 
 finish:
     if (dbus_error_is_set(&error)) {
-        pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
+        if (!dbus_error_has_name(&error, "org.freedesktop.Hal.NoSuchProperty"))
+            pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
         dbus_error_free(&error);
     }
 }
@@ -546,7 +574,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
                     pa_sink *sink;
 
                     if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK))) {
-                        pa_bool_t success = pa_sink_suspend(sink, suspend) >= 0;
+                        pa_bool_t success = pa_sink_suspend(sink, suspend, PA_SUSPEND_SESSION) >= 0;
 
                         if (!success && !suspend)
                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
@@ -559,7 +587,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
                     pa_source *source;
 
                     if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE))) {
-                        pa_bool_t success = pa_source_suspend(source, suspend) >= 0;
+                        pa_bool_t success = pa_source_suspend(source, suspend, PA_SUSPEND_SESSION) >= 0;
 
                         if (!success && !suspend)
                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
@@ -572,7 +600,7 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
                     pa_card *card;
 
                     if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) {
-                        pa_bool_t success = pa_card_suspend(card, suspend) >= 0;
+                        pa_bool_t success = pa_card_suspend(card, suspend, PA_SUSPEND_SESSION) >= 0;
 
                         if (!success && !suspend)
                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
@@ -593,8 +621,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
 
         }
 
-        return DBUS_HANDLER_RESULT_HANDLED;
-
     } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) {
         /* We use this message to avoid a dirty race condition when we
            get an ACLAdded message before the previously owning PA
@@ -616,21 +642,21 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
                     pa_sink *sink;
 
                     if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK)))
-                        pa_sink_suspend(sink, FALSE);
+                        pa_sink_suspend(sink, FALSE, PA_SUSPEND_SESSION);
                 }
 
                 if (d->source_name) {
                     pa_source *source;
 
                     if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE)))
-                        pa_source_suspend(source, FALSE);
+                        pa_source_suspend(source, FALSE, PA_SUSPEND_SESSION);
                 }
 
                 if (d->card_name) {
                     pa_card *card;
 
                     if ((card = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_CARD)))
-                        pa_card_suspend(card, FALSE);
+                        pa_card_suspend(card, FALSE, PA_SUSPEND_SESSION);
                 }
             }
 
@@ -638,7 +664,6 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, vo
             /* Yes, we don't check the UDI for validity, but hopefully HAL will */
             device_added_cb(u->context, udi);
 
-        return DBUS_HANDLER_RESULT_HANDLED;
     }
 
 finish:
@@ -731,7 +756,7 @@ int pa__init(pa_module*m) {
     api = pa_modargs_get_value(ma, "api", "oss");
 #endif
 
-#ifdef HAVE_OSS
+#ifdef HAVE_OSS_OUTPUT
     if (pa_streq(api, "oss"))
         u->capability = CAPABILITY_OSS;
 #endif
@@ -741,6 +766,13 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+#ifdef HAVE_OSS_OUTPUT
+    if (pa_modargs_get_value_boolean(ma, "subdevices", &u->init_subdevs) < 0) {
+        pa_log("Failed to parse subdevices= argument.");
+        goto fail;
+    }
+#endif
+
     if (!(u->connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
         pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message);
         goto fail;