[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-149-g561c0af

Lennart Poettering gitmailer-noreply at 0pointer.de
Fri Jun 5 10:05:23 PDT 2009


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 <lennart at poettering.net>
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 <lennart at poettering.net>
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 <lennart at poettering.net>
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 <lennart at poettering.net>
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-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_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 <lennart at poettering.net>
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 <lennart at poettering.net>
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



More information about the pulseaudio-commits mailing list