This is an automated email from the git hooks/post-receive script. It was
generated because of a push to the "PulseAudio Sound Server" repository.

The master branch has been updated
      from  8bada7496c4d12a033ba54fed98ba796239a1776 (commit)

- Log -----------------------------------------------------------------
561c0af alsa: monitor device reservation status and resume automatically when 
device becomes unused
00797b8 core: add a suspend cause flags field
3af5f8c reserve: wrap device reservation monitor reference implementation
1748fd2 reserve: update reserve.[ch] from upstream git
3e10f3f tdb: include signal.h before tdb.h for compat reasons
4d87475 utils: use pa_path_get_filename() where applicable
-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am                      |    4 +-
 src/daemon/cmdline.c                 |   11 +-
 src/modules/alsa/alsa-sink.c         |   67 ++++++++-
 src/modules/alsa/alsa-source.c       |   67 ++++++++-
 src/modules/module-combine.c         |    4 +-
 src/modules/module-hal-detect.c      |   12 +-
 src/modules/module-suspend-on-idle.c |   12 +-
 src/modules/reserve-monitor.c        |  259 ++++++++++++++++++++++++++++++++++
 src/modules/reserve-monitor.h        |   62 ++++++++
 src/modules/reserve-wrap.c           |  149 +++++++++++++++++++-
 src/modules/reserve-wrap.h           |    9 +-
 src/modules/reserve.c                |   22 +--
 src/modules/reserve.h                |    2 +-
 src/pulsecore/card.c                 |    7 +-
 src/pulsecore/card.h                 |    2 +-
 src/pulsecore/cli-command.c          |    8 +-
 src/pulsecore/cli-text.c             |   10 ++
 src/pulsecore/core.h                 |   10 ++
 src/pulsecore/database-tdb.c         |    3 +
 src/pulsecore/protocol-esound.c      |    4 +-
 src/pulsecore/protocol-native.c      |    8 +-
 src/pulsecore/sink.c                 |   16 ++-
 src/pulsecore/sink.h                 |    5 +-
 src/pulsecore/source.c               |   16 ++-
 src/pulsecore/source.h               |    5 +-
 src/utils/pactl.c                    |   14 +--
 src/utils/pasuspender.c              |    5 +-
 27 files changed, 704 insertions(+), 89 deletions(-)
 create mode 100644 src/modules/reserve-monitor.c
 create mode 100644 src/modules/reserve-monitor.h

-----------------------------------------------------------------------

commit 4d874753f5ba838b015c69f281e991c7a42381eb
Author: Lennart Poettering <[email protected]>
Date:   Thu Jun 4 23:19:48 2009 +0200

    utils: use pa_path_get_filename() where applicable

diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c
index d78089e..ecb3848 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -31,6 +31,7 @@
 
 #include <pulse/xmalloc.h>
 #include <pulse/i18n.h>
+#include <pulse/util.h>
 
 #include <pulsecore/core-util.h>
 #include <pulsecore/strbuf.h>
@@ -109,15 +110,8 @@ static const struct option long_options[] = {
 };
 
 void pa_cmdline_help(const char *argv0) {
-    const char *e;
-
     pa_assert(argv0);
 
-    if ((e = strrchr(argv0, '/')))
-        e++;
-    else
-        e = argv0;
-
     printf(_("%s [options]\n\n"
            "COMMANDS:\n"
            "  -h, --help                            Show this help\n"
@@ -172,7 +166,8 @@ void pa_cmdline_help(const char *argv0) {
            "  -C                                    Open a command line on the 
running TTY\n"
            "                                        after startup\n\n"
 
-           "  -n                                    Don't load default script 
file\n"), e);
+           "  -n                                    Don't load default script 
file\n"),
+           pa_path_get_filename(argv0));
 }
 
 int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int 
*d) {
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 53c6766..6608c01 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -802,7 +802,6 @@ enum {
 
 int main(int argc, char *argv[]) {
     pa_mainloop* m = NULL;
-    char tmp[PATH_MAX];
     int ret = 1, c;
     char *server = NULL, *bn;
 
@@ -882,17 +881,8 @@ int main(int argc, char *argv[]) {
             if (optind+2 < argc)
                 sample_name = pa_xstrdup(argv[optind+2]);
             else {
-                char *f = strrchr(argv[optind+1], '/');
-                size_t n;
-                if (f)
-                    f++;
-                else
-                    f = argv[optind];
-
-                n = strcspn(f, ".");
-                strncpy(tmp, f, n);
-                tmp[n] = 0;
-                sample_name = pa_xstrdup(tmp);
+                char *f = pa_path_get_filename(argv[optind+1]);
+                sample_name = pa_xstrndup(f, strcspn(f, "."));
             }
 
             pa_zero(sfi);
diff --git a/src/utils/pasuspender.c b/src/utils/pasuspender.c
index b4bccd5..c327ee4 100644
--- a/src/utils/pasuspender.c
+++ b/src/utils/pasuspender.c
@@ -235,10 +235,7 @@ int main(int argc, char *argv[]) {
     setlocale(LC_ALL, "");
     bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR);
 
-    if (!(bn = strrchr(argv[0], '/')))
-        bn = argv[0];
-    else
-        bn++;
+    bn = pa_path_get_filename(argv[0]);
 
     while ((c = getopt_long(argc, argv, "s:h", long_options, NULL)) != -1) {
         switch (c) {

commit 3e10f3f4e3bde6bb772eab70a1008895a302494f
Author: Lennart Poettering <[email protected]>
Date:   Thu Jun 4 23:50:43 2009 +0200

    tdb: include signal.h before tdb.h for compat reasons

diff --git a/src/pulsecore/database-tdb.c b/src/pulsecore/database-tdb.c
index c35fd81..b79d283 100644
--- a/src/pulsecore/database-tdb.c
+++ b/src/pulsecore/database-tdb.c
@@ -26,6 +26,9 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <errno.h>
+
+/* Some versions of tdb lack inclusion of signal.h in the header files but use 
sigatomic_t */
+#include <signal.h>
 #include <tdb.h>
 
 #include <pulse/xmalloc.h>

commit 1748fd2a0d327201ee57847ba3d9a8209f8d98d6
Author: Lennart Poettering <[email protected]>
Date:   Fri Jun 5 19:00:12 2009 +0200

    reserve: update reserve.[ch] from upstream git

diff --git a/src/modules/reserve.c b/src/modules/reserve.c
index 9a9591d..09bc46c 100644
--- a/src/modules/reserve.c
+++ b/src/modules/reserve.c
@@ -43,16 +43,15 @@ struct rd_device {
 
        DBusConnection *connection;
 
-       int owning:1;
-       int registered:1;
-       int filtering:1;
-       int gave_up:1;
+       unsigned owning:1;
+       unsigned registered:1;
+       unsigned filtering:1;
+       unsigned gave_up:1;
 
        rd_request_cb_t request_cb;
        void *userdata;
 };
 
-
 #define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
 #define OBJECT_PREFIX "/org/freedesktop/ReserveDevice1/"
 
@@ -297,6 +296,7 @@ static DBusHandlerResult filter_handler(
        dbus_error_init(&error);
 
        d = userdata;
+       assert(d->ref >= 1);
 
        if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameLost")) {
                const char *name;
@@ -560,7 +560,7 @@ void rd_release(
 
        assert(d->ref > 0);
 
-       if (--d->ref)
+       if (--d->ref > 0)
                return;
 
 
@@ -575,17 +575,11 @@ void rd_release(
                        d->connection,
                        d->object_path);
 
-       if (d->owning) {
-               DBusError error;
-               dbus_error_init(&error);
-
+       if (d->owning)
                dbus_bus_release_name(
                        d->connection,
                        d->service_name,
-                       &error);
-
-               dbus_error_free(&error);
-       }
+                       NULL);
 
        free(d->device_name);
        free(d->application_name);
diff --git a/src/modules/reserve.h b/src/modules/reserve.h
index b315a08..3107129 100644
--- a/src/modules/reserve.h
+++ b/src/modules/reserve.h
@@ -45,7 +45,7 @@ typedef int (*rd_request_cb_t)(
  * the error was caused D-Bus. */
 int rd_acquire(
        rd_device **d,                /* On success a pointer to the newly 
allocated rd_device object will be filled in here */
-       DBusConnection *connection,
+       DBusConnection *connection,   /* Session bus (when D-Bus learns about 
user busses we should switchg to user busses) */
        const char *device_name,      /* The device to lock, e.g. "Audio0" */
        const char *application_name, /* A human readable name of the 
application, e.g. "PulseAudio Sound Server" */
        int32_t priority,             /* The priority for this application. If 
unsure use 0 */

commit 3af5f8cb553e512305c1f3603b57424c36c9c82c
Author: Lennart Poettering <[email protected]>
Date:   Fri Jun 5 19:03:16 2009 +0200

    reserve: wrap device reservation monitor reference implementation

diff --git a/src/Makefile.am b/src/Makefile.am
index a7ec691..c0e1806 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1358,7 +1358,7 @@ libalsa_util_la_CFLAGS += $(UDEV_CFLAGS)
 endif
 
 if HAVE_DBUS
-libalsa_util_la_SOURCES += modules/reserve.h modules/reserve.c
+libalsa_util_la_SOURCES += modules/reserve.h modules/reserve.c 
modules/reserve-monitor.h modules/reserve-monitor.c
 libalsa_util_la_LIBADD += $(DBUS_LIBS)
 libalsa_util_la_CFLAGS += $(DBUS_CFLAGS)
 endif
@@ -1670,7 +1670,7 @@ update-sbc:
        done
 
 update-reserve:
-       for i in reserve.c reserve.h ; do \
+       for i in reserve.c reserve.h reserve-monitor.c reserve-monitor.h ; do \
                wget -O modules/$$i 
http://git.0pointer.de/\?p=reserve.git\;a=blob_plain\;f=$$i\;hb=master ; \
        done
 
diff --git a/src/modules/reserve-monitor.c b/src/modules/reserve-monitor.c
new file mode 100644
index 0000000..64d2a7c
--- /dev/null
+++ b/src/modules/reserve-monitor.c
@@ -0,0 +1,259 @@
+/***
+  Copyright 2009 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "reserve-monitor.h"
+
+struct rm_monitor {
+       int ref;
+
+       char *device_name;
+       char *service_name;
+
+       DBusConnection *connection;
+
+       unsigned busy:1;
+       unsigned filtering:1;
+       unsigned matching:1;
+
+       rm_change_cb_t change_cb;
+       void *userdata;
+};
+
+#define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
+
+static DBusHandlerResult filter_handler(
+       DBusConnection *c,
+       DBusMessage *s,
+       void *userdata) {
+
+       DBusMessage *reply;
+       rm_monitor *m;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       m = userdata;
+       assert(m->ref >= 1);
+
+       if (dbus_message_is_signal(s, "org.freedesktop.DBus", 
"NameOwnerChanged")) {
+               const char *name, *old, *new;
+
+               if (!dbus_message_get_args(
+                           s,
+                           &error,
+                           DBUS_TYPE_STRING, &name,
+                           DBUS_TYPE_STRING, &old,
+                           DBUS_TYPE_STRING, &new,
+                           DBUS_TYPE_INVALID))
+                       goto invalid;
+
+               if (strcmp(name, m->service_name) == 0) {
+
+                       m->busy = !!(new && *new);
+
+                       if (m->change_cb) {
+                               m->ref++;
+                               m->change_cb(m);
+                               rm_release(m);
+                       }
+               }
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+invalid:
+       if (!(reply = dbus_message_new_error(
+                     s,
+                     DBUS_ERROR_INVALID_ARGS,
+                     "Invalid arguments")))
+               goto oom;
+
+       if (!dbus_connection_send(c, reply, NULL))
+               goto oom;
+
+       dbus_message_unref(reply);
+
+       dbus_error_free(&error);
+
+       return DBUS_HANDLER_RESULT_HANDLED;
+
+oom:
+       if (reply)
+               dbus_message_unref(reply);
+
+       dbus_error_free(&error);
+
+       return DBUS_HANDLER_RESULT_NEED_MEMORY;
+}
+
+int rm_watch(
+       rm_monitor **_m,
+       DBusConnection *connection,
+       const char*device_name,
+       rm_change_cb_t change_cb,
+       DBusError *error)  {
+
+       rm_monitor *m = NULL;
+       int r;
+       DBusError _error;
+
+       if (!error)
+               error = &_error;
+
+       dbus_error_init(error);
+
+       if (!_m)
+               return -EINVAL;
+
+       if (!connection)
+               return -EINVAL;
+
+       if (!device_name)
+               return -EINVAL;
+
+       if (!(m = calloc(sizeof(rm_monitor), 1)))
+               return -ENOMEM;
+
+       m->ref = 1;
+
+       if (!(m->device_name = strdup(device_name))) {
+               r = -ENOMEM;
+               goto fail;
+       }
+
+       m->connection = dbus_connection_ref(connection);
+       m->change_cb = change_cb;
+
+       if (!(m->service_name = malloc(sizeof(SERVICE_PREFIX) + 
strlen(device_name)))) {
+               r = -ENOMEM;
+               goto fail;
+       }
+       sprintf(m->service_name, SERVICE_PREFIX "%s", m->device_name);
+
+       if (!(dbus_connection_add_filter(m->connection, filter_handler, m, 
NULL))) {
+               r = -ENOMEM;
+               goto fail;
+       }
+
+       m->filtering = 1;
+
+       dbus_bus_add_match(m->connection,
+                          "type='signal',"
+                          "sender='" DBUS_SERVICE_DBUS "',"
+                          "interface='" DBUS_INTERFACE_DBUS "',"
+                          "member='NameOwnerChanged'", error);
+
+       if (dbus_error_is_set(error)) {
+               r = -EIO;
+               goto fail;
+       }
+
+       m->matching = 1;
+
+       m->busy = dbus_bus_name_has_owner(m->connection, m->service_name, 
error);
+
+       if (dbus_error_is_set(error)) {
+               r = -EIO;
+               goto fail;
+       }
+
+       *_m = m;
+       return 0;
+
+fail:
+       if (&_error == error)
+               dbus_error_free(&_error);
+
+       if (m)
+               rm_release(m);
+
+       return r;
+}
+
+void rm_release(rm_monitor *m) {
+       if (!m)
+               return;
+
+       assert(m->ref > 0);
+
+       if (--m->ref > 0)
+               return;
+
+       if (m->matching)
+               dbus_bus_remove_match(
+                       m->connection,
+                       "type='signal',"
+                       "sender='" DBUS_SERVICE_DBUS "',"
+                       "interface='" DBUS_INTERFACE_DBUS "',"
+                       "member='NameOwnerChanged'", NULL);
+
+       if (m->filtering)
+               dbus_connection_remove_filter(
+                       m->connection,
+                       filter_handler,
+                       m);
+
+       free(m->device_name);
+       free(m->service_name);
+
+       if (m->connection)
+               dbus_connection_unref(m->connection);
+
+       free(m);
+}
+
+int rm_busy(rm_monitor *m) {
+       if (!m)
+               return -EINVAL;
+
+       assert(m->ref > 0);
+
+       return m->busy;
+}
+
+void rm_set_userdata(rm_monitor *m, void *userdata) {
+
+       if (!m)
+               return;
+
+       assert(m->ref > 0);
+       m->userdata = userdata;
+}
+
+void* rm_get_userdata(rm_monitor *m) {
+
+       if (!m)
+               return NULL;
+
+       assert(m->ref > 0);
+
+       return m->userdata;
+}
diff --git a/src/modules/reserve-monitor.h b/src/modules/reserve-monitor.h
new file mode 100644
index 0000000..4f4a833
--- /dev/null
+++ b/src/modules/reserve-monitor.h
@@ -0,0 +1,62 @@
+#ifndef fooreservemonitorhfoo
+#define fooreservemonitorhfoo
+
+/***
+  Copyright 2009 Lennart Poettering
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+***/
+
+#include <dbus/dbus.h>
+#include <inttypes.h>
+
+typedef struct rm_monitor rm_monitor;
+
+/* Prototype for a function that is called whenever the reservation
+ * device of a device changes. Use rm_monitor_busy() to find out the
+ * new state.*/
+typedef void (*rm_change_cb_t)(rm_monitor *m);
+
+/* Creates a monitor for watching the lock status of a device. Returns
+ * 0 on success, a negative errno style return value on error.  The
+ * DBus error might be set as well if the error was caused D-Bus. */
+int rm_watch(
+       rm_monitor **m,              /* On success a pointer to the newly 
allocated rm_device object will be filled in here */
+       DBusConnection *connection,  /* Session bus (when D-Bus learns about 
user busses we should switchg to user busses) */
+       const char *device_name,     /* The device to monitor, e.g. "Audio0" */
+       rm_change_cb_t change_cb,    /* Will be called whenever the lock status 
changes. May be NULL */
+       DBusError *error);           /* If we fail due to a D-Bus related issue 
the error will be filled in here. May be NULL. */
+
+/* Free a rm_monitor object */
+void rm_release(rm_monitor *m);
+
+/* Checks whether the device is currently reserved, and returns 1
+ * then, 0 if not, negative errno style error code value on error. */
+int rm_busy(rm_monitor *m);
+
+/* Attach a userdata pointer to an rm_monitor */
+void rm_set_userdata(rm_monitor *m, void *userdata);
+
+/* Query the userdata pointer from an rm_monitor. Returns NULL if no
+ * userdata was set. */
+void* rm_get_userdata(rm_monitor *m);
+
+#endif
diff --git a/src/modules/reserve-wrap.c b/src/modules/reserve-wrap.c
index d0d014d..07b592d 100644
--- a/src/modules/reserve-wrap.c
+++ b/src/modules/reserve-wrap.c
@@ -35,6 +35,7 @@
 #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);
 
@@ -191,3 +203,138 @@ 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;
+    int k;
+    char *t;
+#ifdef HAVE_DBUS
+    DBusError error;
+
+    dbus_error_init(&error);
+#endif
+
+    pa_assert(c);
+    pa_assert(device_name);
+
+    t = pa_sprintf_malloc("reserve-monitor-wrap...@%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_warn("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_warn("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;
+}
+
+pa_bool_t pa_reserve_monitor_wrapper_busy(pa_reserve_monitor_wrapper *w) {
+    pa_assert(w);
+
+    pa_assert(PA_REFCNT_VALUE(w) >= 1);
+
+    return rm_busy(w->monitor) > 0;
+}
diff --git a/src/modules/reserve-wrap.h b/src/modules/reserve-wrap.h
index 2b97c91..2de6c09 100644
--- a/src/modules/reserve-wrap.h
+++ b/src/modules/reserve-wrap.h
@@ -28,11 +28,18 @@
 typedef struct pa_reserve_wrapper pa_reserve_wrapper;
 
 pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char 
*device_name);
-
 void pa_reserve_wrapper_unref(pa_reserve_wrapper *r);
 
 pa_hook* pa_reserve_wrapper_hook(pa_reserve_wrapper *r);
 
 void pa_reserve_wrapper_set_application_device_name(pa_reserve_wrapper *r, 
const char *name);
 
+typedef struct pa_reserve_monitor_wrapper pa_reserve_monitor_wrapper;
+
+pa_reserve_monitor_wrapper* pa_reserve_monitor_wrapper_get(pa_core *c, const 
char *device_name);
+void pa_reserve_monitor_wrapper_unref(pa_reserve_monitor_wrapper *m);
+
+pa_hook* pa_reserve_monitor_wrapper_hook(pa_reserve_monitor_wrapper *m);
+pa_bool_t pa_reserve_monitor_wrapper_busy(pa_reserve_monitor_wrapper *m);
+
 #endif

commit 00797b8b6ea7978f862facb7181fb04895caf23c
Author: Lennart Poettering <[email protected]>
Date:   Fri Jun 5 19:05:07 2009 +0200

    core: add a suspend cause flags field

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 59f5311..b1adc52 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -124,7 +124,7 @@ static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, 
void *forced, struct u
     pa_assert(r);
     pa_assert(u);
 
-    if (pa_sink_suspend(u->sink, TRUE) < 0)
+    if (pa_sink_suspend(u->sink, TRUE, PA_SUSPEND_APPLICATION) < 0)
         return PA_HOOK_CANCEL;
 
     return PA_HOOK_OK;
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index f1c1819..68f697d 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -122,7 +122,7 @@ static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, 
void *forced, struct u
     pa_assert(r);
     pa_assert(u);
 
-    if (pa_source_suspend(u->source, TRUE) < 0)
+    if (pa_source_suspend(u->source, TRUE, PA_SUSPEND_APPLICATION) < 0)
         return PA_HOOK_CANCEL;
 
     return PA_HOOK_OK;
diff --git a/src/modules/module-combine.c b/src/modules/module-combine.c
index 02a7e1f..725faa0 100644
--- a/src/modules/module-combine.c
+++ b/src/modules/module-combine.c
@@ -593,7 +593,7 @@ static void unsuspend(struct userdata *u) {
     /* Let's resume */
     for (o = pa_idxset_first(u->outputs, &idx); o; o = 
pa_idxset_next(u->outputs, &idx)) {
 
-        pa_sink_suspend(o->sink, FALSE);
+        pa_sink_suspend(o->sink, FALSE, PA_SUSPEND_IDLE);
 
         if (PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
             enable_output(o);
@@ -873,7 +873,7 @@ static struct output *output_new(struct userdata *u, 
pa_sink *sink) {
     }
 
     if (PA_SINK_IS_OPENED(state) || state == PA_SINK_INIT) {
-        pa_sink_suspend(sink, FALSE);
+        pa_sink_suspend(sink, FALSE, PA_SUSPEND_IDLE);
 
         if (PA_SINK_IS_OPENED(pa_sink_get_state(sink)))
             if (output_create_sink_input(o) < 0)
diff --git a/src/modules/module-hal-detect.c b/src/modules/module-hal-detect.c
index b6139e4..9ac8705 100644
--- a/src/modules/module-hal-detect.c
+++ b/src/modules/module-hal-detect.c
@@ -567,7 +567,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 */
@@ -580,7 +580,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 */
@@ -593,7 +593,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 */
@@ -637,21 +637,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);
                 }
             }
 
diff --git a/src/modules/module-suspend-on-idle.c 
b/src/modules/module-suspend-on-idle.c
index cc69d74..c5b7891 100644
--- a/src/modules/module-suspend-on-idle.c
+++ b/src/modules/module-suspend-on-idle.c
@@ -86,14 +86,14 @@ static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, 
const struct timeval
 
     d->userdata->core->mainloop->time_restart(d->time_event, NULL);
 
-    if (d->sink && pa_sink_check_suspend(d->sink) <= 0 && 
pa_sink_get_state(d->sink) != PA_SINK_SUSPENDED) {
+    if (d->sink && pa_sink_check_suspend(d->sink) <= 0 && 
!(d->sink->suspend_cause & PA_SUSPEND_IDLE)) {
         pa_log_info("Sink %s idle for too long, suspending ...", 
d->sink->name);
-        pa_sink_suspend(d->sink, TRUE);
+        pa_sink_suspend(d->sink, TRUE, PA_SUSPEND_IDLE);
     }
 
-    if (d->source && pa_source_check_suspend(d->source) <= 0 && 
pa_source_get_state(d->source) != PA_SOURCE_SUSPENDED) {
+    if (d->source && pa_source_check_suspend(d->source) <= 0 && 
!(d->source->suspend_cause & PA_SUSPEND_IDLE)) {
         pa_log_info("Source %s idle for too long, suspending ...", 
d->source->name);
-        pa_source_suspend(d->source, TRUE);
+        pa_source_suspend(d->source, TRUE, PA_SUSPEND_IDLE);
     }
 }
 
@@ -127,13 +127,13 @@ static void resume(struct device_info *d) {
     d->userdata->core->mainloop->time_restart(d->time_event, NULL);
 
     if (d->sink) {
-        pa_sink_suspend(d->sink, FALSE);
+        pa_sink_suspend(d->sink, FALSE, PA_SUSPEND_IDLE);
 
         pa_log_debug("Sink %s becomes busy.", d->sink->name);
     }
 
     if (d->source) {
-        pa_source_suspend(d->source, FALSE);
+        pa_source_suspend(d->source, FALSE, PA_SUSPEND_IDLE);
 
         pa_log_debug("Source %s becomes busy.", d->source->name);
     }
diff --git a/src/pulsecore/card.c b/src/pulsecore/card.c
index 8101a92..59b8cda 100644
--- a/src/pulsecore/card.c
+++ b/src/pulsecore/card.c
@@ -244,19 +244,20 @@ int pa_card_set_profile(pa_card *c, const char *name, 
pa_bool_t save) {
     return 0;
 }
 
-int pa_card_suspend(pa_card *c, pa_bool_t suspend) {
+int pa_card_suspend(pa_card *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
     pa_sink *sink;
     pa_source *source;
     uint32_t idx;
     int ret = 0;
 
     pa_assert(c);
+    pa_assert(cause != 0);
 
     for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = 
pa_idxset_next(c->sinks, &idx))
-        ret -= pa_sink_suspend(sink, suspend) < 0;
+        ret -= pa_sink_suspend(sink, suspend, cause) < 0;
 
     for (source = pa_idxset_first(c->sources, &idx); source; source = 
pa_idxset_next(c->sources, &idx))
-        ret -= pa_source_suspend(source, suspend) < 0;
+        ret -= pa_source_suspend(source, suspend, cause) < 0;
 
     return ret;
 }
diff --git a/src/pulsecore/card.h b/src/pulsecore/card.h
index 3b7608f..415ab67 100644
--- a/src/pulsecore/card.h
+++ b/src/pulsecore/card.h
@@ -99,6 +99,6 @@ void pa_card_free(pa_card *c);
 
 int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save);
 
-int pa_card_suspend(pa_card *c, pa_bool_t suspend);
+int pa_card_suspend(pa_card *c, pa_bool_t suspend, pa_suspend_cause_t cause);
 
 #endif
diff --git a/src/pulsecore/cli-command.c b/src/pulsecore/cli-command.c
index dad647a..644de96 100644
--- a/src/pulsecore/cli-command.c
+++ b/src/pulsecore/cli-command.c
@@ -1278,7 +1278,7 @@ static int pa_cli_command_suspend_sink(pa_core *c, 
pa_tokenizer *t, pa_strbuf *b
         return -1;
     }
 
-    if ((r = pa_sink_suspend(sink, suspend)) < 0)
+    if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
         pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", 
pa_strerror(r));
 
     return 0;
@@ -1314,7 +1314,7 @@ static int pa_cli_command_suspend_source(pa_core *c, 
pa_tokenizer *t, pa_strbuf
         return -1;
     }
 
-    if ((r = pa_source_suspend(source, suspend)) < 0)
+    if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
         pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", 
pa_strerror(r));
 
     return 0;
@@ -1339,10 +1339,10 @@ static int pa_cli_command_suspend(pa_core *c, 
pa_tokenizer *t, pa_strbuf *buf, p
         return -1;
     }
 
-    if ((r = pa_sink_suspend_all(c, suspend)) < 0)
+    if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
         pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", 
pa_strerror(r));
 
-    if ((r = pa_source_suspend_all(c, suspend)) < 0)
+    if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
         pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", 
pa_strerror(r));
 
     return 0;
diff --git a/src/pulsecore/cli-text.c b/src/pulsecore/cli-text.c
index 604678b..bc863f0 100644
--- a/src/pulsecore/cli-text.c
+++ b/src/pulsecore/cli-text.c
@@ -232,6 +232,7 @@ char *pa_sink_list_to_string(pa_core *c) {
             "\tdriver: <%s>\n"
             "\tflags: %s%s%s%s%s%s%s%s\n"
             "\tstate: %s\n"
+            "\tsuspend cause: %s%s%s%s\n"
             "\tvolume: %s%s%s\n"
             "\t        balance %0.2f\n"
             "\tbase volume: %s%s%s\n"
@@ -258,6 +259,10 @@ char *pa_sink_list_to_string(pa_core *c) {
             sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
             sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
             sink_state_to_string(pa_sink_get_state(sink)),
+            sink->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
+            sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "",
+            sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
+            sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
             pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, 
FALSE)),
             sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t        " : "",
             sink->flags & PA_SINK_DECIBEL_VOLUME ? 
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, 
FALSE)) : "",
@@ -335,6 +340,7 @@ char *pa_source_list_to_string(pa_core *c) {
             "\tdriver: <%s>\n"
             "\tflags: %s%s%s%s%s%s%s\n"
             "\tstate: %s\n"
+            "\tsuspend cause: %s%s%s%s\n"
             "\tvolume: %s%s%s\n"
             "\t        balance %0.2f\n"
             "\tbase volume: %s%s%s\n"
@@ -358,6 +364,10 @@ char *pa_source_list_to_string(pa_core *c) {
             source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
             source->flags & PA_SOURCE_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
             source_state_to_string(pa_source_get_state(source)),
+            source->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
+            source->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : 
"",
+            source->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
+            source->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
             pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, 
FALSE)),
             source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t        " : "",
             source->flags & PA_SOURCE_DECIBEL_VOLUME ? 
pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_source_get_volume(source, 
FALSE)) : "",
diff --git a/src/pulsecore/core.h b/src/pulsecore/core.h
index c679444..09a880c 100644
--- a/src/pulsecore/core.h
+++ b/src/pulsecore/core.h
@@ -27,6 +27,16 @@
 
 typedef struct pa_core pa_core;
 
+/* This is a bitmask that encodes the cause why a sink/source is
+ * suspended. */
+typedef enum pa_suspend_cause {
+    PA_SUSPEND_USER = 1,         /* Exposed to the user via some protocol */
+    PA_SUSPEND_APPLICATION = 2,  /* Used by the device reservation logic */
+    PA_SUSPEND_IDLE = 4,         /* Used by module-suspend-on-idle */
+    PA_SUSPEND_SESSION = 8,      /* Used by module-hal for mark inactive 
sessions */
+    PA_SUSPEND_ALL = 0xFFFF      /* Magic cause that can be used to resume 
forcibly */
+} pa_suspend_cause_t;
+
 #include <pulsecore/idxset.h>
 #include <pulsecore/hashmap.h>
 #include <pulsecore/memblock.h>
diff --git a/src/pulsecore/protocol-esound.c b/src/pulsecore/protocol-esound.c
index 7e7126e..ad7cd04 100644
--- a/src/pulsecore/protocol-esound.c
+++ b/src/pulsecore/protocol-esound.c
@@ -947,10 +947,10 @@ static int esd_proto_standby_or_resume(connection *c, 
esd_proto_t request, const
     connection_write(c, &ok, sizeof(int32_t));
 
     if (request == ESD_PROTO_STANDBY)
-        ok = pa_sink_suspend_all(c->protocol->core, TRUE) >= 0;
+        ok = pa_sink_suspend_all(c->protocol->core, TRUE, PA_SUSPEND_USER) >= 
0;
     else {
         pa_assert(request == ESD_PROTO_RESUME);
-        ok = pa_sink_suspend_all(c->protocol->core, FALSE) >= 0;
+        ok = pa_sink_suspend_all(c->protocol->core, FALSE, PA_SUSPEND_USER) >= 
0;
     }
 
     connection_write(c, &ok, sizeof(int32_t));
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index d4a9952..e9e2d60 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -4098,7 +4098,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa
 
             pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
 
-            if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
+            if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 
0) {
                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
                 return;
             }
@@ -4112,7 +4112,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa
 
             CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
 
-            if (pa_sink_suspend(sink, b) < 0) {
+            if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
                 return;
             }
@@ -4125,7 +4125,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa
 
             pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
 
-            if (pa_source_suspend_all(c->protocol->core, b) < 0) {
+            if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 
0) {
                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
                 return;
             }
@@ -4140,7 +4140,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t 
command, uint32_t tag, pa
 
             CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
 
-            if (pa_source_suspend(source, b) < 0) {
+            if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
                 pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
                 return;
             }
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 28b3440..3c4adc6 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -190,6 +190,7 @@ pa_sink* pa_sink_new(
     s->core = core;
     s->state = PA_SINK_INIT;
     s->flags = flags;
+    s->suspend_cause = 0;
     s->name = pa_xstrdup(name);
     s->proplist = pa_proplist_copy(data->proplist);
     s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
@@ -499,11 +500,19 @@ int pa_sink_update_status(pa_sink*s) {
 }
 
 /* Called from main context */
-int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
+int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
     pa_sink_assert_ref(s);
     pa_assert(PA_SINK_IS_LINKED(s->state));
+    pa_assert(cause != 0);
 
     if (suspend)
+        s->suspend_cause |= cause;
+    else
+        s->suspend_cause &= ~cause;
+
+    pa_log_debug("Suspend cause of sink %s is 0x%04x, %s", s->name, 
s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
+
+    if (s->suspend_cause)
         return sink_set_state(s, PA_SINK_SUSPENDED);
     else
         return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : 
PA_SINK_IDLE);
@@ -1823,17 +1832,18 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void 
*userdata, int64_t offse
 }
 
 /* Called from main thread */
-int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
+int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t 
cause) {
     pa_sink *sink;
     uint32_t idx;
     int ret = 0;
 
     pa_core_assert_ref(c);
+    pa_assert(cause != 0);
 
     for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = 
PA_SINK(pa_idxset_next(c->sinks, &idx))) {
         int r;
 
-        if ((r = pa_sink_suspend(sink, suspend)) < 0)
+        if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
             ret = r;
     }
 
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index e33b3cf..4dce3f9 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -56,6 +56,7 @@ struct pa_sink {
     pa_core *core;
     pa_sink_state_t state;
     pa_sink_flags_t flags;
+    pa_suspend_cause_t suspend_cause;
 
     char *name;
     char *driver;                           /* may be NULL */
@@ -252,8 +253,8 @@ size_t pa_sink_get_max_rewind(pa_sink *s);
 size_t pa_sink_get_max_request(pa_sink *s);
 
 int pa_sink_update_status(pa_sink*s);
-int pa_sink_suspend(pa_sink *s, pa_bool_t suspend);
-int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
+int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause);
+int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t 
cause);
 
 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume);
 void pa_sink_propagate_flat_volume(pa_sink *s);
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index 8aeb560..4ade18f 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -180,6 +180,7 @@ pa_source* pa_source_new(
     s->core = core;
     s->state = PA_SOURCE_INIT;
     s->flags = flags;
+    s->suspend_cause = 0;
     s->name = pa_xstrdup(name);
     s->proplist = pa_proplist_copy(data->proplist);
     s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
@@ -427,14 +428,22 @@ int pa_source_update_status(pa_source*s) {
 }
 
 /* Called from main context */
-int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
+int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t 
cause) {
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
+    pa_assert(cause != 0);
 
     if (s->monitor_of)
         return -PA_ERR_NOTSUPPORTED;
 
     if (suspend)
+        s->suspend_cause |= cause;
+    else
+        s->suspend_cause &= ~cause;
+
+    pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, 
s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
+
+    if (suspend)
         return source_set_state(s, PA_SOURCE_SUSPENDED);
     else
         return source_set_state(s, pa_source_used_by(s) ? PA_SOURCE_RUNNING : 
PA_SOURCE_IDLE);
@@ -1032,12 +1041,13 @@ int pa_source_process_msg(pa_msgobject *object, int 
code, void *userdata, int64_
 }
 
 /* Called from main thread */
-int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
+int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t 
cause) {
     uint32_t idx;
     pa_source *source;
     int ret = 0;
 
     pa_core_assert_ref(c);
+    pa_assert(cause != 0);
 
     for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source 
= PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
         int r;
@@ -1045,7 +1055,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
         if (source->monitor_of)
             continue;
 
-        if ((r = pa_source_suspend(source, suspend)) < 0)
+        if ((r = pa_source_suspend(source, suspend, cause)) < 0)
             ret = r;
     }
 
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index 2978f57..1fbed70 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -58,6 +58,7 @@ struct pa_source {
     pa_core *core;
     pa_source_state_t state;
     pa_source_flags_t flags;
+    pa_suspend_cause_t suspend_cause;
 
     char *name;
     char *driver;                             /* may be NULL */
@@ -231,8 +232,8 @@ void pa_source_get_latency_range(pa_source *s, pa_usec_t 
*min_latency, pa_usec_t
 size_t pa_source_get_max_rewind(pa_source *s);
 
 int pa_source_update_status(pa_source*s);
-int pa_source_suspend(pa_source *s, pa_bool_t suspend);
-int pa_source_suspend_all(pa_core *c, pa_bool_t suspend);
+int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t 
cause);
+int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t 
cause);
 
 void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
 const pa_cvolume *pa_source_get_volume(pa_source *source, pa_bool_t 
force_refresh);

commit 561c0af8518dd8a2bac07284d306b0970c304f9f
Author: Lennart Poettering <[email protected]>
Date:   Fri Jun 5 19:05:42 2009 +0200

    alsa: monitor device reservation status and resume automatically when 
device becomes unused

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index b1adc52..98ebac3 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -116,6 +116,8 @@ struct userdata {
 
     pa_reserve_wrapper *reserve;
     pa_hook_slot *reserve_slot;
+    pa_reserve_monitor_wrapper *monitor;
+    pa_hook_slot *monitor_slot;
 };
 
 static void userdata_free(struct userdata *u);
@@ -185,6 +187,57 @@ static int reserve_init(struct userdata *u, const char 
*dname) {
     return 0;
 }
 
+static pa_hook_result_t monitor_cb(pa_reserve_monitor_wrapper *w, void* busy, 
struct userdata *u) {
+    pa_bool_t b;
+
+    pa_assert(w);
+    pa_assert(u);
+
+    b = PA_PTR_TO_UINT(busy) && !u->reserve;
+
+    pa_sink_suspend(u->sink, b, PA_SUSPEND_APPLICATION);
+    return PA_HOOK_OK;
+}
+
+static void monitor_done(struct userdata *u) {
+    pa_assert(u);
+
+    if (u->monitor_slot) {
+        pa_hook_slot_free(u->monitor_slot);
+        u->monitor_slot = NULL;
+    }
+
+    if (u->monitor) {
+        pa_reserve_monitor_wrapper_unref(u->monitor);
+        u->monitor = NULL;
+    }
+}
+
+static int reserve_monitor_init(struct userdata *u, const char *dname) {
+    char *rname;
+
+    pa_assert(u);
+    pa_assert(dname);
+
+    if (pa_in_system_mode())
+        return 0;
+
+    /* We are resuming, try to lock the device */
+    if (!(rname = pa_alsa_get_reserve_name(dname)))
+        return 0;
+
+    u->monitor = pa_reserve_monitor_wrapper_get(u->core, rname);
+    pa_xfree(rname);
+
+    if (!(u->monitor))
+        return -1;
+
+    pa_assert(!u->monitor_slot);
+    u->monitor_slot = 
pa_hook_connect(pa_reserve_monitor_wrapper_hook(u->monitor), PA_HOOK_NORMAL, 
(pa_hook_cb_t) monitor_cb, u);
+
+    return 0;
+}
+
 static void fix_min_sleep_wakeup(struct userdata *u) {
     size_t max_use, max_use_2;
 
@@ -1580,9 +1633,14 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, 
const char*driver, pa_ca
             pa_rtclock_usec(),
             TRUE);
 
-    if (reserve_init(u, pa_modargs_get_value(
-                             ma, "device_id",
-                             pa_modargs_get_value(ma, "device", 
DEFAULT_DEVICE))) < 0)
+    dev_id = pa_modargs_get_value(
+            ma, "device_id",
+            pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
+
+    if (reserve_init(u, dev_id) < 0)
+        goto fail;
+
+    if (reserve_monitor_init(u, dev_id) < 0)
         goto fail;
 
     b = use_mmap;
@@ -1828,6 +1886,7 @@ static void userdata_free(struct userdata *u) {
         pa_smoother_free(u->smoother);
 
     reserve_done(u);
+    monitor_done(u);
 
     pa_xfree(u->device_name);
     pa_xfree(u);
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index 68f697d..277b110 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -114,6 +114,8 @@ struct userdata {
 
     pa_reserve_wrapper *reserve;
     pa_hook_slot *reserve_slot;
+    pa_reserve_monitor_wrapper *monitor;
+    pa_hook_slot *monitor_slot;
 };
 
 static void userdata_free(struct userdata *u);
@@ -183,6 +185,57 @@ static int reserve_init(struct userdata *u, const char 
*dname) {
     return 0;
 }
 
+static pa_hook_result_t monitor_cb(pa_reserve_monitor_wrapper *w, void* busy, 
struct userdata *u) {
+    pa_bool_t b;
+
+    pa_assert(w);
+    pa_assert(u);
+
+    b = PA_PTR_TO_UINT(busy) && !u->reserve;
+
+    pa_source_suspend(u->source, b, PA_SUSPEND_APPLICATION);
+    return PA_HOOK_OK;
+}
+
+static void monitor_done(struct userdata *u) {
+    pa_assert(u);
+
+    if (u->monitor_slot) {
+        pa_hook_slot_free(u->monitor_slot);
+        u->monitor_slot = NULL;
+    }
+
+    if (u->monitor) {
+        pa_reserve_monitor_wrapper_unref(u->monitor);
+        u->monitor = NULL;
+    }
+}
+
+static int reserve_monitor_init(struct userdata *u, const char *dname) {
+    char *rname;
+
+    pa_assert(u);
+    pa_assert(dname);
+
+    if (pa_in_system_mode())
+        return 0;
+
+    /* We are resuming, try to lock the device */
+    if (!(rname = pa_alsa_get_reserve_name(dname)))
+        return 0;
+
+    u->monitor = pa_reserve_monitor_wrapper_get(u->core, rname);
+    pa_xfree(rname);
+
+    if (!(u->monitor))
+        return -1;
+
+    pa_assert(!u->monitor_slot);
+    u->monitor_slot = 
pa_hook_connect(pa_reserve_monitor_wrapper_hook(u->monitor), PA_HOOK_NORMAL, 
(pa_hook_cb_t) monitor_cb, u);
+
+    return 0;
+}
+
 static void fix_min_sleep_wakeup(struct userdata *u) {
     size_t max_use, max_use_2;
     pa_assert(u);
@@ -1438,9 +1491,14 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs 
*ma, const char*driver, p
             pa_rtclock_usec(),
             FALSE);
 
-    if (reserve_init(u, pa_modargs_get_value(
-                             ma, "device_id",
-                             pa_modargs_get_value(ma, "device", 
DEFAULT_DEVICE))) < 0)
+    dev_id = pa_modargs_get_value(
+            ma, "device_id",
+            pa_modargs_get_value(ma, "device", DEFAULT_DEVICE));
+
+    if (reserve_init(u, dev_id) < 0)
+        goto fail;
+
+    if (reserve_monitor_init(u, dev_id) < 0)
         goto fail;
 
     b = use_mmap;
@@ -1676,6 +1734,7 @@ static void userdata_free(struct userdata *u) {
         pa_smoother_free(u->smoother);
 
     reserve_done(u);
+    monitor_done(u);
 
     pa_xfree(u->device_name);
     pa_xfree(u);

-- 
hooks/post-receive
PulseAudio Sound Server
_______________________________________________
pulseaudio-commits mailing list
[email protected]
https://tango.0pointer.de/mailman/listinfo/pulseaudio-commits

Reply via email to