]> code.delx.au - pulseaudio/blobdiff - src/modules/reserve-wrap.c
modules: Fix resource leak in stream-restore
[pulseaudio] / src / modules / reserve-wrap.c
index d0d014d3324e5d41e24abf58ce7c3107d4587bfa..9c69d59c2a3555d37706e99c8e62e901ccfa1696 100644 (file)
 #include <errno.h>
 
 #include <pulse/xmalloc.h>
-#include <pulse/i18n.h>
 
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-util.h>
+#include <pulsecore/i18n.h>
 #include <pulsecore/shared.h>
 
 #ifdef HAVE_DBUS
 #include <pulsecore/dbus-shared.h>
 #include "reserve.h"
+#include "reserve-monitor.h"
 #endif
 
 #include "reserve-wrap.h"
@@ -50,6 +51,17 @@ struct pa_reserve_wrapper {
 #endif
 };
 
+struct pa_reserve_monitor_wrapper {
+    PA_REFCNT_DECLARE;
+    pa_core *core;
+    pa_hook hook;
+    char *shared_name;
+#ifdef HAVE_DBUS
+    pa_dbus_connection *connection;
+    struct rm_monitor *monitor;
+#endif
+};
+
 static void reserve_wrapper_free(pa_reserve_wrapper *r) {
     pa_assert(r);
 
@@ -83,7 +95,7 @@ static int request_cb(rd_device *d, int forced) {
     PA_REFCNT_INC(r);
 
     k = pa_hook_fire(&r->hook, PA_INT_TO_PTR(forced));
-    pa_log_debug("Device unlock has been requested and %s.", k < 0 ? "failed" : "succeeded");
+    pa_log_debug("Device unlock of %s has been requested and %s.", r->shared_name, k < 0 ? "failed" : "succeeded");
 
     pa_reserve_wrapper_unref(r);
 
@@ -93,9 +105,9 @@ static int request_cb(rd_device *d, int forced) {
 
 pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name) {
     pa_reserve_wrapper *r;
-    int k;
     char *t;
 #ifdef HAVE_DBUS
+    int k;
     DBusError error;
 
     dbus_error_init(&error);
@@ -125,7 +137,7 @@ pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name)
 
 #ifdef HAVE_DBUS
     if (!(r->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
-        pa_log_warn("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
+        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
 
         /* We don't treat this as error here because we want allow PA
          * to run even when no session bus is available. */
@@ -142,10 +154,10 @@ pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name)
                  NULL)) < 0) {
 
         if (k == -EBUSY) {
-            pa_log_error("Device '%s' already locked.", device_name);
+            pa_log_debug("Device '%s' already locked.", device_name);
             goto fail;
         } else {
-            pa_log_warn("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));
+            pa_log_debug("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));
             return r;
         }
     }
@@ -191,3 +203,142 @@ void pa_reserve_wrapper_set_application_device_name(pa_reserve_wrapper *r, const
     rd_set_application_device_name(r->device, name);
 #endif
 }
+
+static void reserve_monitor_wrapper_free(pa_reserve_monitor_wrapper *w) {
+    pa_assert(w);
+
+#ifdef HAVE_DBUS
+    if (w->monitor)
+        rm_release(w->monitor);
+
+    if (w->connection)
+        pa_dbus_connection_unref(w->connection);
+#endif
+
+    pa_hook_done(&w->hook);
+
+    if (w->shared_name) {
+        pa_assert_se(pa_shared_remove(w->core, w->shared_name) >= 0);
+        pa_xfree(w->shared_name);
+    }
+
+    pa_xfree(w);
+}
+
+#ifdef HAVE_DBUS
+static void change_cb(rm_monitor *m) {
+    pa_reserve_monitor_wrapper *w;
+    int k;
+
+    pa_assert(m);
+    pa_assert_se(w = rm_get_userdata(m));
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    PA_REFCNT_INC(w);
+
+    if ((k = rm_busy(w->monitor)) < 0)
+        return;
+
+    pa_hook_fire(&w->hook, PA_INT_TO_PTR(!!k));
+    pa_log_debug("Device lock status of %s changed: %s", w->shared_name, k ? "busy" : "not busy");
+
+    pa_reserve_monitor_wrapper_unref(w);
+}
+#endif
+
+pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const char *device_name) {
+    pa_reserve_monitor_wrapper *w;
+    char *t;
+#ifdef HAVE_DBUS
+    int k;
+    DBusError error;
+
+    dbus_error_init(&error);
+#endif
+
+    pa_assert(c);
+    pa_assert(device_name);
+
+    t = pa_sprintf_malloc("reserve-monitor-wrapper@%s", device_name);
+
+    if ((w = pa_shared_get(c, t))) {
+        pa_xfree(t);
+
+        pa_assert(PA_REFCNT_VALUE(w) >= 1);
+        PA_REFCNT_INC(w);
+
+        return w;
+    }
+
+    w = pa_xnew0(pa_reserve_monitor_wrapper, 1);
+    PA_REFCNT_INIT(w);
+    w->core = c;
+    pa_hook_init(&w->hook, w);
+    w->shared_name = t;
+
+    pa_assert_se(pa_shared_set(c, w->shared_name, w) >= 0);
+
+#ifdef HAVE_DBUS
+    if (!(w->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
+        pa_log_debug("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
+
+        /* We don't treat this as error here because we want allow PA
+         * to run even when no session bus is available. */
+        return w;
+    }
+
+    if ((k = rm_watch(
+                 &w->monitor,
+                 pa_dbus_connection_get(w->connection),
+                 device_name,
+                 change_cb,
+                 NULL)) < 0) {
+
+        pa_log_debug("Failed to create watch on device '%s': %s", device_name, pa_cstrerror(-k));
+        goto fail;
+    }
+
+    pa_log_debug("Successfully create reservation lock monitor for device '%s'", device_name);
+
+    rm_set_userdata(w->monitor, w);
+    return w;
+
+fail:
+    dbus_error_free(&error);
+
+    reserve_monitor_wrapper_free(w);
+
+    return NULL;
+#else
+    return w;
+#endif
+}
+
+void pa_reserve_monitor_wrapper_unref(pa_reserve_monitor_wrapper *w) {
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    if (PA_REFCNT_DEC(w) > 0)
+        return;
+
+    reserve_monitor_wrapper_free(w);
+}
+
+pa_hook* pa_reserve_monitor_wrapper_hook(pa_reserve_monitor_wrapper *w) {
+    pa_assert(w);
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    return &w->hook;
+}
+
+bool pa_reserve_monitor_wrapper_busy(pa_reserve_monitor_wrapper *w) {
+    pa_assert(w);
+
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+#ifdef HAVE_DBUS
+    return rm_busy(w->monitor) > 0;
+#else
+    return false;
+#endif
+}