diff options
Diffstat (limited to 'src/modules/module-hal-detect.c')
| -rw-r--r-- | src/modules/module-hal-detect.c | 186 | 
1 files changed, 157 insertions, 29 deletions
| diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c index 84ac0ce4..ca22d70b 100644 --- a/src/modules/module-hal-detect.c +++ b/src/modules/module-hal-detect.c @@ -44,6 +44,8 @@  #include <pulsecore/hashmap.h>  #include <pulsecore/idxset.h>  #include <pulsecore/core-util.h> +#include <pulsecore/namereg.h> +#include <pulsecore/core-scache.h>  #include <hal/libhal.h> @@ -57,6 +59,7 @@ PA_MODULE_VERSION(PACKAGE_VERSION)  struct device {      uint32_t index;      char *udi; +    char *sink_name, *source_name;  };  struct userdata { @@ -79,6 +82,8 @@ static void hal_device_free(struct device* d) {      pa_assert(d);      pa_xfree(d->udi); +    pa_xfree(d->sink_name); +    pa_xfree(d->source_name);      pa_xfree(d);  } @@ -136,15 +141,22 @@ static int hal_alsa_device_is_modem(LibHalContext *context, const char *udi, DBu      return r;  } -static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi) { +static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi, char **sink_name, char **source_name) {      char args[128];      alsa_type_t type;      int device, card;      const char *module_name;      DBusError error; +    pa_module *m;      dbus_error_init(&error); +    pa_assert(u); +    pa_assert(sink_name); +    pa_assert(source_name); + +    *sink_name = *source_name = NULL; +          type = hal_alsa_device_get_type(u->context, udi, &error);      if (dbus_error_is_set(&error) || type == ALSA_TYPE_OTHER)          goto fail; @@ -161,16 +173,28 @@ static pa_module* hal_device_load_alsa(struct userdata *u, const char *udi) {          goto fail;      if (type == ALSA_TYPE_SINK) { +        *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); +                  module_name = "module-alsa-sink"; -        pa_snprintf(args, sizeof(args), "device=hw:%u sink_name=alsa_output.%s", card, strip_udi(udi)); +        pa_snprintf(args, sizeof(args), "device=hw:%u sink_name=%s", card, *sink_name);      } else { +        *source_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); +                  module_name = "module-alsa-source"; -        pa_snprintf(args, sizeof(args), "device=hw:%u source_name=alsa_input.%s", card, strip_udi(udi)); +        pa_snprintf(args, sizeof(args), "device=hw:%u source_name=%s", card, *source_name);      }      pa_log_debug("Loading %s with arguments '%s'", module_name, args); -    return pa_module_load(u->core, module_name, args); +    m = pa_module_load(u->core, module_name, args); + +    if (!m) { +        pa_xfree(*sink_name); +        pa_xfree(*source_name); +        *sink_name = *source_name = NULL; +    } +     +    return m;  fail:      if (dbus_error_is_set(&error)) { @@ -219,13 +243,20 @@ finish:      return r;  } -static pa_module* hal_device_load_oss(struct userdata *u, const char *udi) { +static pa_module* hal_device_load_oss(struct userdata *u, const char *udi, char **sink_name, char **source_name) {      char args[256];      char* device;      DBusError error; +    pa_module *m;      dbus_error_init(&error); +    pa_assert(u); +    pa_assert(sink_name); +    pa_assert(source_name); + +    *sink_name = *source_name = NULL; +      if (!hal_oss_device_is_pcm(u->context, udi, &error) || dbus_error_is_set(&error))          goto fail; @@ -233,12 +264,23 @@ static pa_module* hal_device_load_oss(struct userdata *u, const char *udi) {      if (!device || dbus_error_is_set(&error))          goto fail; -    pa_snprintf(args, sizeof(args), "device=%s sink_name=oss_output.%s source_name=oss_input.%s", device, strip_udi(udi), strip_udi(udi)); +    *sink_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); +    *source_name = pa_sprintf_malloc("alsa_output.%s", strip_udi(udi)); +     +    pa_snprintf(args, sizeof(args), "device=%s sink_name=%s source_name=%s", device, sink_name, source_name);      libhal_free_string(device);      pa_log_debug("Loading module-oss with arguments '%s'", args); -    return pa_module_load(u->core, "module-oss", args); +    m = pa_module_load(u->core, "module-oss", args); + +    if (!m) { +        pa_xfree(*sink_name); +        pa_xfree(*source_name); +        *sink_name = *source_name = NULL; +    } + +    return m;  fail:      if (dbus_error_is_set(&error)) { @@ -250,31 +292,34 @@ fail:  }  #endif -static int hal_device_add(struct userdata *u, const char *udi) { +static struct device* hal_device_add(struct userdata *u, const char *udi) {      pa_module* m = NULL;      struct device *d; +    char *sink_name = NULL, *source_name = NULL;      pa_assert(u);      pa_assert(u->capability);  #ifdef HAVE_ALSA      if (strcmp(u->capability, CAPABILITY_ALSA) == 0) -        m = hal_device_load_alsa(u, udi); +        m = hal_device_load_alsa(u, udi, &sink_name, &source_name);  #endif  #ifdef HAVE_OSS      if (strcmp(u->capability, CAPABILITY_OSS) == 0) -        m = hal_device_load_oss(u, udi); +        m = hal_device_load_oss(u, udi, &sink_name, &source_name);  #endif      if (!m) -        return -1; +        return NULL;      d = pa_xnew(struct device, 1);      d->udi = pa_xstrdup(udi);      d->index = m->index; +    d->sink_name = sink_name; +    d->source_name = source_name;      pa_hashmap_put(u->devices, d->udi, d); -    return 0; +    return d;  }  static int hal_device_add_all(struct userdata *u, const char *capability) { @@ -300,10 +345,15 @@ static int hal_device_add_all(struct userdata *u, const char *capability) {          u->capability = capability;          for (i = 0; i < n; i++) { -            if (hal_device_add(u, udis[i]) < 0) +            struct device *d; +             +            if (!(d = hal_device_add(u, udis[i])))                  pa_log_debug("Not loaded device %s", udis[i]); -            else +            else { +                if (d->sink_name) +                    pa_scache_play_item_by_name(u->core, "pulse-coldplug", d->sink_name, PA_VOLUME_NORM, 0);                  count++; +            }          }      } @@ -325,6 +375,7 @@ static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, const s      DBusError error;      struct timerdata *td = userdata;      int b; +    struct device *d;      dbus_error_init(&error); @@ -333,8 +384,14 @@ static void device_added_time_cb(pa_mainloop_api *ea, pa_time_event *ev, const s      if (dbus_error_is_set(&error)) {          pa_log_error("Error adding device: %s: %s", error.name, error.message);          dbus_error_free(&error); -    } else if (b) -        hal_device_add(td->u, td->udi); +    } else if (b) { +        if (!(d = hal_device_add(td->u, td->udi)))  +            pa_log_debug("Not loaded device %s", td->udi); +        else { +            if (d->sink_name) +                pa_scache_play_item_by_name(td->u->core, "pulse-hotplug", d->sink_name, PA_VOLUME_NORM, 0); +        } +    }      pa_xfree(td->udi);      pa_xfree(td); @@ -446,6 +503,66 @@ static void lost_capability_cb(LibHalContext *context, const char *udi, const ch          device_removed_cb(context, udi);  } + +static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) { +    struct userdata*u = userdata; +    DBusError error; + +    pa_assert(bus); +    pa_assert(message); +    pa_assert(u); +     +    dbus_error_init(&error); + +    pa_log_debug("dbus: interface=%s, path=%s, member=%s\n", +                 dbus_message_get_interface(message), +                 dbus_message_get_path(message), +                 dbus_message_get_member(message)); + +    if (dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLAdded") || +        dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLRemoved")) { +        uint32_t uid; +        int suspend = strcmp(dbus_message_get_member(message), "ACLRemoved") == 0; +         +        if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) { +            pa_log_error("Failed to parse ACL message: %s: %s", error.name, error.message); +            goto finish; +        } + +        if (uid == getuid() || uid == geteuid()) { +            struct device *d; +            const char *udi; + +            udi = dbus_message_get_path(message); +             +            if ((d = pa_hashmap_get(u->devices, udi))) { +                 +                if (d->sink_name) { +                    pa_sink *sink; +                     +                    if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK, 0))) +                        if (pa_sink_suspend(sink, suspend) >= 0) +                            pa_scache_play_item_by_name(u->core, "pulse-access", d->sink_name, PA_VOLUME_NORM, 0); +                } + +                if (d->source_name) { +                    pa_source *source; + +                    if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE, 0))) +                        pa_source_suspend(source, suspend); +                } +            } + +        } +         +    } + +finish: +    dbus_error_free(&error); +         +    return DBUS_HANDLER_RESULT_HANDLED; +} +  static void hal_context_free(LibHalContext* hal_context) {      DBusError error; @@ -454,8 +571,7 @@ static void hal_context_free(LibHalContext* hal_context) {      libhal_ctx_shutdown(hal_context, &error);      libhal_ctx_free(hal_context); -    if (dbus_error_is_set(&error)) -        dbus_error_free(&error); +    dbus_error_free(&error);  }  static LibHalContext* hal_context_new(pa_core* c, DBusConnection *conn) { @@ -485,8 +601,7 @@ fail:      if (hal_context)          hal_context_free(hal_context); -    if (dbus_error_is_set(&error)) -        dbus_error_free(&error); +    dbus_error_free(&error);      return NULL;  } @@ -503,16 +618,17 @@ int pa__init(pa_core *c, pa_module*m) {      dbus_error_init(&error); -    if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error))) { +    if (!(conn = pa_dbus_bus_get(c, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) { +        if (conn) +            pa_dbus_connection_unref(conn);          pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message); -        dbus_error_free(&error); -        return -1; +        goto fail;      }      if (!(hal_context = hal_context_new(c, pa_dbus_connection_get(conn)))) {          /* pa_hal_context_new() logs appropriate errors */          pa_dbus_connection_unref(conn); -        return -1; +        goto fail;      }      u = pa_xnew(struct userdata, 1); @@ -539,18 +655,30 @@ int pa__init(pa_core *c, pa_module*m) {      libhal_ctx_set_device_new_capability(hal_context, new_capability_cb);      libhal_ctx_set_device_lost_capability(hal_context, lost_capability_cb); -    dbus_error_init(&error); -          if (!libhal_device_property_watch_all(hal_context, &error)) {          pa_log_error("Error monitoring device list: %s: %s", error.name, error.message); -        dbus_error_free(&error); -        pa__done(c, m); -        return -1; +        goto fail;      } +    if (!dbus_connection_add_filter(pa_dbus_connection_get(conn), filter_cb, u, NULL)) { +        pa_log_error("Failed to add filter function"); +        goto fail; +    } + +    dbus_bus_add_match(pa_dbus_connection_get(conn), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error); +    if (dbus_error_is_set(&error)) { +        pa_log_error("Unable to subscribe to HAL ACL signals: %s: %s", error.name, error.message); +        goto fail; +    } +          pa_log_info("Loaded %i modules.", n);      return 0; + +fail: +    dbus_error_free(&error); +    pa__done(c, m); +    return -1;  } | 
