[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.15-test2-127-gba3c766

Lennart Poettering gitmailer-noreply at 0pointer.de
Mon Feb 23 21:38:16 PST 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  fb49399a0cf8c6e42f4c3f25dbe4753add4251f8 (commit)

- Log -----------------------------------------------------------------
ba3c766... update reserve.c from upstream git
c341010... implement device reservation scheme
3c73025... in case alsa lies to use don't spin forever
ec9f8f1... if ALSA gives us nonsensical data at least try to fix it up a little
9eb5070... introduce new well-known role 'a11y'
-----------------------------------------------------------------------

Summary of changes:
 src/Makefile.am                                    |   13 +-
 src/modules/alsa/alsa-sink.c                       |  104 ++++
 src/modules/alsa/alsa-source.c                     |   99 +++
 src/modules/alsa/alsa-util.c                       |   40 ++-
 src/modules/alsa/alsa-util.h                       |    2 +
 src/modules/alsa/module-alsa-card.c                |   16 +-
 src/modules/reserve-wrap.c                         |  158 +++++
 .../auth-cookie.h => modules/reserve-wrap.h}       |   17 +-
 src/modules/reserve.c                              |  635 ++++++++++++++++++++
 src/modules/reserve.h                              |   68 +++
 src/pulse/proplist.h                               |    2 +-
 11 files changed, 1139 insertions(+), 15 deletions(-)
 create mode 100644 src/modules/reserve-wrap.c
 copy src/{pulsecore/auth-cookie.h => modules/reserve-wrap.h} (67%)
 create mode 100644 src/modules/reserve.c
 create mode 100644 src/modules/reserve.h

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

commit 9eb50701b6a6e8e5b74236bc954e94097eb7e680
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Feb 24 01:44:46 2009 +0100

    introduce new well-known role 'a11y'

diff --git a/src/pulse/proplist.h b/src/pulse/proplist.h
index 7a58568..d30dc3b 100644
--- a/src/pulse/proplist.h
+++ b/src/pulse/proplist.h
@@ -51,7 +51,7 @@ PA_C_DECL_BEGIN
 /** For streams: an XDG icon name for the media. e.g. "audio-x-mp3" */
 #define PA_PROP_MEDIA_ICON_NAME                "media.icon_name"
 
-/** For streams: logic role of this media. One of the strings "video", "music", "game", "event", "phone", "animation", "production" */
+/** For streams: logic role of this media. One of the strings "video", "music", "game", "event", "phone", "animation", "production", "a11y" */
 #define PA_PROP_MEDIA_ROLE                     "media.role"
 
 /** For event sound streams: XDG event sound name. e.g. "message-new-email" (Event sound streams are those with media.role set to "event") */

commit ec9f8f10f358ededa1dec0e3f7f57669fce58547
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Feb 24 06:06:04 2009 +0100

    if ALSA gives us nonsensical data at least try to fix it up a little

diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 8eedeeb..30d57e0 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1574,8 +1574,8 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa
 
     k = (size_t) n * pa_frame_size(ss);
 
-    if (k >= hwbuf_size * 3 ||
-        k >= pa_bytes_per_second(ss)*10)
+    if (k >= hwbuf_size * 5 ||
+        k >= pa_bytes_per_second(ss)*10) {
 
         PA_ONCE_BEGIN {
             char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
@@ -1587,6 +1587,10 @@ snd_pcm_sframes_t pa_alsa_safe_avail(snd_pcm_t *pcm, size_t hwbuf_size, const pa
             pa_xfree(dn);
         } PA_ONCE_END;
 
+        /* Mhmm, let's try not to fail completely */
+        n = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
+    }
+
     return n;
 }
 
@@ -1610,8 +1614,8 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_si
 
     abs_k = k >= 0 ? (size_t) k : (size_t) -k;
 
-    if (abs_k >= hwbuf_size * 3 ||
-        abs_k >= pa_bytes_per_second(ss)*10)
+    if (abs_k >= hwbuf_size * 5 ||
+        abs_k >= pa_bytes_per_second(ss)*10) {
 
         PA_ONCE_BEGIN {
             char *dn = pa_alsa_get_driver_name_by_pcm(pcm);
@@ -1624,6 +1628,13 @@ int pa_alsa_safe_delay(snd_pcm_t *pcm, snd_pcm_sframes_t *delay, size_t hwbuf_si
             pa_xfree(dn);
         } PA_ONCE_END;
 
+        /* Mhmm, let's try not to fail completely */
+        if (k < 0)
+            *delay = -(snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
+        else
+            *delay = (snd_pcm_sframes_t) (hwbuf_size / pa_frame_size(ss));
+    }
+
     return 0;
 }
 

commit 3c73025bf52bf7e652f6f8e7ff59b6e10790bdfc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Feb 24 06:11:42 2009 +0100

    in case alsa lies to use don't spin forever

diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index d4a54fe..0a1ebb1 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -255,6 +255,7 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
     pa_bool_t work_done = TRUE;
     pa_usec_t max_sleep_usec = 0, process_usec = 0;
     size_t left_to_play;
+    unsigned j = 0;
 
     pa_assert(u);
     pa_sink_assert_ref(u->sink);
@@ -320,6 +321,15 @@ static int mmap_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
             break;
         }
 
+
+        if (++j > 10) {
+#ifdef DEBUG_TIMING
+            pa_log_debug("Not filling up, because already too many iterations.");
+#endif
+
+            break;
+        }
+
         n_bytes -= u->hwbuf_unused;
         polled = FALSE;
 
@@ -399,6 +409,7 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
     pa_bool_t work_done = FALSE;
     pa_usec_t max_sleep_usec = 0, process_usec = 0;
     size_t left_to_play;
+    unsigned j = 0;
 
     pa_assert(u);
     pa_sink_assert_ref(u->sink);
@@ -449,6 +460,14 @@ static int unix_write(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polle
             break;
         }
 
+        if (++j > 10) {
+#ifdef DEBUG_TIMING
+            pa_log_debug("Not filling up, because already too many iterations.");
+#endif
+
+            break;
+        }
+
         n_bytes -= u->hwbuf_unused;
         polled = FALSE;
 
diff --git a/src/modules/alsa/alsa-source.c b/src/modules/alsa/alsa-source.c
index f2dad4c..ad9a7f2 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -248,6 +248,7 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
     pa_bool_t work_done = FALSE;
     pa_usec_t max_sleep_usec = 0, process_usec = 0;
     size_t left_to_record;
+    unsigned j = 0;
 
     pa_assert(u);
     pa_source_assert_ref(u->source);
@@ -303,6 +304,14 @@ static int mmap_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
             break;
         }
 
+        if (++j > 10) {
+#ifdef DEBUG_TIMING
+            pa_log_debug("Not filling up, because already too many iterations.");
+#endif
+
+            break;
+        }
+
         polled = FALSE;
 
 #ifdef DEBUG_TIMING
@@ -381,6 +390,7 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
     int work_done = FALSE;
     pa_usec_t max_sleep_usec = 0, process_usec = 0;
     size_t left_to_record;
+    unsigned j = 0;
 
     pa_assert(u);
     pa_source_assert_ref(u->source);
@@ -424,6 +434,14 @@ static int unix_read(struct userdata *u, pa_usec_t *sleep_usec, pa_bool_t polled
             break;
         }
 
+        if (++j > 10) {
+#ifdef DEBUG_TIMING
+            pa_log_debug("Not filling up, because already too many iterations.");
+#endif
+
+            break;
+        }
+
         polled = FALSE;
 
         for (;;) {

commit c341010304064c9a6ae13fab15c7fa7883acaeeb
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Feb 24 06:13:39 2009 +0100

    implement device reservation scheme

diff --git a/src/Makefile.am b/src/Makefile.am
index 4b467f8..1fc8735 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1309,10 +1309,16 @@ libalsa_util_la_CFLAGS = $(AM_CFLAGS) $(ASOUNDLIB_CFLAGS)
 
 if HAVE_HAL
 libalsa_util_la_SOURCES += modules/hal-util.h modules/hal-util.c
-libalsa_util_la_LIBADD += $(HAL_LIBS) libdbus-util.la
+libalsa_util_la_LIBADD += $(HAL_LIBS)
 libalsa_util_la_CFLAGS += $(HAL_CFLAGS)
 endif
 
+if HAVE_DBUS
+libalsa_util_la_SOURCES += modules/reserve.h modules/reserve.c modules/reserve-wrap.c modules/reserve-wrap.h
+libalsa_util_la_LIBADD += $(DBUS_LIBS)
+libalsa_util_la_CFLAGS += $(DBUS_CFLAGS)
+endif
+
 module_alsa_sink_la_SOURCES = modules/alsa/module-alsa-sink.c
 module_alsa_sink_la_LDFLAGS = $(MODULE_LDFLAGS)
 module_alsa_sink_la_LIBADD = $(AM_LIBADD) $(ASOUNDLIB_LIBS) libalsa-util.la libpulsecore- at PA_MAJORMINORMICRO@.la libpulsecommon- at PA_MAJORMINORMICRO@.la libpulse.la
@@ -1614,6 +1620,11 @@ update-sbc:
 		wget -O modules/bluetooth/$$i http://git.kernel.org/\?p=bluetooth/bluez.git\;a=blob_plain\;f=audio/$$i ; \
 	done
 
+update-reserve:
+	for i in reserve.c reserve.h ; do \
+		wget -O modules/$$i http://git.0pointer.de/\?p=reserve.git\;a=blob_plain\;f=$$i\;hb=master ; \
+	done
+
 # Automatically generate linker version script. We use the same one for all public .sos
 update-map-file:
 	( echo "PULSE_0 {" ; \
diff --git a/src/modules/alsa/alsa-sink.c b/src/modules/alsa/alsa-sink.c
index 0a1ebb1..83fc9e1 100644
--- a/src/modules/alsa/alsa-sink.c
+++ b/src/modules/alsa/alsa-sink.c
@@ -53,6 +53,8 @@
 #include <pulsecore/rtclock.h>
 #include <pulsecore/time-smoother.h>
 
+#include <modules/reserve-wrap.h>
+
 #include "alsa-util.h"
 #include "alsa-sink.h"
 
@@ -101,10 +103,62 @@ struct userdata {
     pa_smoother *smoother;
     uint64_t write_count;
     uint64_t since_start;
+
+    pa_reserve_wrapper *reserve;
+    pa_hook_slot *reserve_slot;
 };
 
 static void userdata_free(struct userdata *u);
 
+static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) {
+    pa_assert(r);
+    pa_assert(u);
+
+    if (pa_sink_suspend(u->sink, TRUE) < 0)
+        return PA_HOOK_CANCEL;
+
+    return PA_HOOK_OK;
+}
+
+static void reserve_done(struct userdata *u) {
+    pa_assert(u);
+
+    if (u->reserve_slot) {
+        pa_hook_slot_free(u->reserve_slot);
+        u->reserve_slot = NULL;
+    }
+
+    if (u->reserve) {
+        pa_reserve_wrapper_unref(u->reserve);
+        u->reserve = NULL;
+    }
+}
+
+static int reserve_init(struct userdata *u, const char *dname) {
+    char *rname;
+
+    pa_assert(u);
+    pa_assert(dname);
+
+    if (u->reserve)
+        return 0;
+
+    /* We are resuming, try to lock the device */
+    if (!(rname = pa_alsa_get_reserve_name(dname)))
+        return 0;
+
+    u->reserve = pa_reserve_wrapper_get(u->core, rname);
+    pa_xfree(rname);
+
+    if (!(u->reserve))
+        return -1;
+
+    pa_assert(!u->reserve_slot);
+    u->reserve_slot = pa_hook_connect(pa_reserve_wrapper_hook(u->reserve), PA_HOOK_NORMAL, (pa_hook_cb_t) reserve_cb, u);
+
+    return 0;
+}
+
 static void fix_min_sleep_wakeup(struct userdata *u) {
     size_t max_use, max_use_2;
 
@@ -601,6 +655,7 @@ static int build_pollfd(struct userdata *u) {
     return 0;
 }
 
+/* Called from IO context */
 static int suspend(struct userdata *u) {
     pa_assert(u);
     pa_assert(u->pcm_handle);
@@ -622,6 +677,7 @@ static int suspend(struct userdata *u) {
     return 0;
 }
 
+/* Called from IO context */
 static int update_sw_params(struct userdata *u) {
     snd_pcm_uframes_t avail_min;
     int err;
@@ -677,6 +733,7 @@ static int update_sw_params(struct userdata *u) {
     return 0;
 }
 
+/* Called from IO context */
 static int unsuspend(struct userdata *u) {
     pa_sample_spec ss;
     int err;
@@ -749,6 +806,7 @@ fail:
     return -1;
 }
 
+/* Called from IO context */
 static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
     struct userdata *u = PA_SINK(o)->userdata;
 
@@ -804,6 +862,25 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
     return pa_sink_process_msg(o, code, data, offset, chunk);
 }
 
+/* Called from main context */
+static int sink_set_state_cb(pa_sink *s, pa_sink_state_t new_state) {
+    pa_sink_state_t old_state;
+    struct userdata *u;
+
+    pa_sink_assert_ref(s);
+    pa_assert_se(u = s->userdata);
+
+    old_state = pa_sink_get_state(u->sink);
+
+    if (PA_SINK_IS_OPENED(old_state) && new_state == PA_SINK_SUSPENDED)
+        reserve_done(u);
+    else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state))
+        if (reserve_init(u, u->device_name) < 0)
+            return -1;
+
+    return 0;
+}
+
 static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
     struct userdata *u = snd_mixer_elem_get_callback_private(elem);
 
@@ -1468,6 +1545,11 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
     pa_smoother_set_time_offset(u->smoother, usec);
     pa_smoother_pause(u->smoother, usec);
 
+    if (reserve_init(u, pa_modargs_get_value(
+                             ma, "device_id",
+                             pa_modargs_get_value(ma, "device", DEFAULT_DEVICE))) < 0)
+        goto fail;
+
     b = use_mmap;
     d = use_tsched;
 
@@ -1569,6 +1651,7 @@ pa_sink *pa_alsa_sink_new(pa_module *m, pa_modargs *ma, const char*driver, pa_ca
 
     u->sink->parent.process_msg = sink_process_msg;
     u->sink->update_requested_latency = sink_update_requested_latency_cb;
+    u->sink->set_state = sink_set_state_cb;
     u->sink->userdata = u;
 
     pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
@@ -1681,6 +1764,8 @@ static void userdata_free(struct userdata *u) {
     if (u->smoother)
         pa_smoother_free(u->smoother);
 
+    reserve_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 ad9a7f2..2f0e94c 100644
--- a/src/modules/alsa/alsa-source.c
+++ b/src/modules/alsa/alsa-source.c
@@ -54,6 +54,8 @@
 #include <pulsecore/time-smoother.h>
 #include <pulsecore/rtclock.h>
 
+#include <modules/reserve-wrap.h>
+
 #include "alsa-util.h"
 #include "alsa-source.h"
 
@@ -99,10 +101,62 @@ struct userdata {
 
     pa_smoother *smoother;
     uint64_t read_count;
+
+    pa_reserve_wrapper *reserve;
+    pa_hook_slot *reserve_slot;
 };
 
 static void userdata_free(struct userdata *u);
 
+static pa_hook_result_t reserve_cb(pa_reserve_wrapper *r, void *forced, struct userdata *u) {
+    pa_assert(r);
+    pa_assert(u);
+
+    if (pa_source_suspend(u->source, TRUE) < 0)
+        return PA_HOOK_CANCEL;
+
+    return PA_HOOK_OK;
+}
+
+static void reserve_done(struct userdata *u) {
+    pa_assert(u);
+
+    if (u->reserve_slot) {
+        pa_hook_slot_free(u->reserve_slot);
+        u->reserve_slot = NULL;
+    }
+
+    if (u->reserve) {
+        pa_reserve_wrapper_unref(u->reserve);
+        u->reserve = NULL;
+    }
+}
+
+static int reserve_init(struct userdata *u, const char *dname) {
+    char *rname;
+
+    pa_assert(u);
+    pa_assert(dname);
+
+    if (u->reserve)
+        return 0;
+
+    /* We are resuming, try to lock the device */
+    if (!(rname = pa_alsa_get_reserve_name(dname)))
+        return 0;
+
+    u->reserve = pa_reserve_wrapper_get(u->core, rname);
+    pa_xfree(rname);
+
+    if (!(u->reserve))
+        return -1;
+
+    pa_assert(!u->reserve_slot);
+    u->reserve_slot = pa_hook_connect(pa_reserve_wrapper_hook(u->reserve), PA_HOOK_NORMAL, (pa_hook_cb_t) reserve_cb, u);
+
+    return 0;
+}
+
 static void fix_min_sleep_wakeup(struct userdata *u) {
     size_t max_use, max_use_2;
     pa_assert(u);
@@ -765,6 +819,25 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
     return pa_source_process_msg(o, code, data, offset, chunk);
 }
 
+/* Called from main context */
+static int source_set_state_cb(pa_source *s, pa_source_state_t new_state) {
+    pa_source_state_t old_state;
+    struct userdata *u;
+
+    pa_source_assert_ref(s);
+    pa_assert_se(u = s->userdata);
+
+    old_state = pa_source_get_state(u->source);
+
+    if (PA_SINK_IS_OPENED(old_state) && new_state == PA_SINK_SUSPENDED)
+        reserve_done(u);
+    else if (old_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(new_state))
+        if (reserve_init(u, u->device_name) < 0)
+            return -1;
+
+    return 0;
+}
+
 static int mixer_callback(snd_mixer_elem_t *elem, unsigned int mask) {
     struct userdata *u = snd_mixer_elem_get_callback_private(elem);
 
@@ -1316,6 +1389,11 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
     u->smoother = pa_smoother_new(DEFAULT_TSCHED_WATERMARK_USEC*2, DEFAULT_TSCHED_WATERMARK_USEC*2, TRUE, 5);
     pa_smoother_set_time_offset(u->smoother, pa_rtclock_usec());
 
+    if (reserve_init(u, pa_modargs_get_value(
+                             ma, "device_id",
+                             pa_modargs_get_value(ma, "device", DEFAULT_DEVICE))) < 0)
+        goto fail;
+
     b = use_mmap;
     d = use_tsched;
 
@@ -1414,6 +1492,7 @@ pa_source *pa_alsa_source_new(pa_module *m, pa_modargs *ma, const char*driver, p
 
     u->source->parent.process_msg = source_process_msg;
     u->source->update_requested_latency = source_update_requested_latency_cb;
+    u->source->set_state = source_set_state_cb;
     u->source->userdata = u;
 
     pa_source_set_asyncmsgq(u->source, u->thread_mq.inq);
@@ -1519,6 +1598,8 @@ static void userdata_free(struct userdata *u) {
     if (u->smoother)
         pa_smoother_free(u->smoother);
 
+    reserve_done(u);
+
     pa_xfree(u->device_name);
     pa_xfree(u);
 }
diff --git a/src/modules/alsa/alsa-util.c b/src/modules/alsa/alsa-util.c
index 30d57e0..ec20d1d 100644
--- a/src/modules/alsa/alsa-util.c
+++ b/src/modules/alsa/alsa-util.c
@@ -1708,3 +1708,24 @@ char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm) {
 
     return pa_alsa_get_driver_name(card);
 }
+
+char *pa_alsa_get_reserve_name(const char *device) {
+    const char *t;
+    int i;
+
+    pa_assert(device);
+
+    if ((t = strchr(device, ':')))
+        device = t+1;
+
+    if ((i = snd_card_get_index(device)) < 0) {
+        int32_t k;
+
+        if (pa_atoi(device, &k) < 0)
+            return NULL;
+
+        i = (int) k;
+    }
+
+    return pa_sprintf_malloc("Audio%i", i);
+}
diff --git a/src/modules/alsa/alsa-util.h b/src/modules/alsa/alsa-util.h
index eddc41b..899532e 100644
--- a/src/modules/alsa/alsa-util.h
+++ b/src/modules/alsa/alsa-util.h
@@ -136,4 +136,6 @@ char *pa_alsa_get_driver_name(int card);
 
 char *pa_alsa_get_driver_name_by_pcm(snd_pcm_t *pcm);
 
+char *pa_alsa_get_reserve_name(const char *device);
+
 #endif
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index c949435..52e64ea 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -30,6 +30,8 @@
 #include <pulsecore/modargs.h>
 #include <pulsecore/queue.h>
 
+#include <modules/reserve-wrap.h>
+
 #include "alsa-util.h"
 #include "alsa-sink.h"
 #include "alsa-source.h"
@@ -273,11 +275,13 @@ static void set_card_name(pa_card_new_data *data, pa_modargs *ma, const char *de
     pa_xfree(t);
 }
 
-int pa__init(pa_module*m) {
+int pa__init(pa_module *m) {
     pa_card_new_data data;
     pa_modargs *ma;
     int alsa_card_index;
     struct userdata *u;
+    char rname[32];
+    pa_reserve_wrapper *reserve = NULL;
 
     pa_alsa_redirect_errors_inc();
     snd_config_update_free_global();
@@ -303,6 +307,11 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
+    pa_snprintf(rname, sizeof(rname), "Audio%i", alsa_card_index);
+
+    if (!(reserve = pa_reserve_wrapper_get(m->core, rname)))
+        goto fail;
+
     pa_card_new_data_init(&data);
     data.driver = __FILE__;
     data.module = m;
@@ -335,11 +344,16 @@ int pa__init(pa_module*m) {
 
     init_profile(u);
 
+    pa_reserve_wrapper_unref(reserve);
+
     return 0;
 
 fail:
+    if (reserve)
+        pa_reserve_wrapper_unref(reserve);
 
     pa__done(m);
+
     return -1;
 }
 
diff --git a/src/modules/reserve-wrap.c b/src/modules/reserve-wrap.c
new file mode 100644
index 0000000..df2861f
--- /dev/null
+++ b/src/modules/reserve-wrap.c
@@ -0,0 +1,158 @@
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2009 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/xmalloc.h>
+#include <pulse/i18n.h>
+
+#include <pulsecore/core-error.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/shared.h>
+
+#include <modules/dbus-util.h>
+
+#include "reserve.h"
+#include "reserve-wrap.h"
+
+struct pa_reserve_wrapper {
+    PA_REFCNT_DECLARE;
+    pa_core *core;
+    pa_dbus_connection *connection;
+    pa_hook hook;
+    struct rd_device *device;
+    char *shared_name;
+};
+
+static void reserve_wrapper_free(pa_reserve_wrapper *r) {
+    pa_assert(r);
+
+    if (r->device)
+        rd_release(r->device);
+
+    pa_hook_done(&r->hook);
+
+    if (r->connection)
+        pa_dbus_connection_unref(r->connection);
+
+    if (r->shared_name) {
+        pa_assert_se(pa_shared_remove(r->core, r->shared_name) >= 0);
+        pa_xfree(r->shared_name);
+    }
+
+    pa_xfree(r);
+}
+
+static int request_cb(rd_device *d, int forced) {
+    pa_reserve_wrapper *r;
+    int k;
+
+    pa_assert(d);
+    pa_assert_se(r = rd_get_userdata(d));
+    pa_assert(PA_REFCNT_VALUE(r) >= 1);
+
+    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_reserve_wrapper_unref(r);
+
+    return k < 0 ? -1 : 1;
+}
+
+pa_reserve_wrapper* pa_reserve_wrapper_get(pa_core *c, const char *device_name) {
+    pa_reserve_wrapper *r;
+    DBusError error;
+    int k;
+    char *t;
+
+    dbus_error_init(&error);
+
+    pa_assert(c);
+    pa_assert(device_name);
+
+    t = pa_sprintf_malloc("reserve-wrapper@%s", device_name);
+
+    if ((r = pa_shared_get(c, t))) {
+        pa_xfree(t);
+
+        pa_assert(PA_REFCNT_VALUE(r) >= 1);
+        PA_REFCNT_INC(r);
+
+        return r;
+    }
+
+    r = pa_xnew0(pa_reserve_wrapper, 1);
+    PA_REFCNT_INIT(r);
+    r->core = c;
+    pa_hook_init(&r->hook, r);
+    r->shared_name = t;
+
+    pa_assert_se(pa_shared_set(c, r->shared_name, r) >= 0);
+
+    if (!(r->connection = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
+        pa_log_error("Unable to contact D-Bus session bus: %s: %s", error.name, error.message);
+        goto fail;
+    }
+
+    if ((k = rd_acquire(
+                 &r->device,
+                 pa_dbus_connection_get(r->connection),
+                 device_name,
+                 _("PulseAudio Sound Server"),
+                 0,
+                 request_cb,
+                 &error)) < 0) {
+
+        pa_log_error("Failed to acquire reservation lock on device '%s': %s", device_name, pa_cstrerror(-k));
+        goto fail;
+    }
+
+    pa_log_debug("Successfully acquired reservation lock on device '%s'", device_name);
+
+    rd_set_userdata(r->device, r);
+
+    return r;
+
+fail:
+    reserve_wrapper_free(r);
+    return NULL;
+}
+
+void pa_reserve_wrapper_unref(pa_reserve_wrapper *r) {
+    pa_assert(r);
+    pa_assert(PA_REFCNT_VALUE(r) >= 1);
+
+    if (PA_REFCNT_DEC(r) > 0)
+        return;
+
+    reserve_wrapper_free(r);
+}
+
+pa_hook* pa_reserve_wrapper_hook(pa_reserve_wrapper *r) {
+    pa_assert(r);
+    pa_assert(PA_REFCNT_VALUE(r) >= 1);
+
+    return &r->hook;
+}
diff --git a/src/modules/reserve-wrap.h b/src/modules/reserve-wrap.h
new file mode 100644
index 0000000..7afc511
--- /dev/null
+++ b/src/modules/reserve-wrap.h
@@ -0,0 +1,36 @@
+#ifndef fooreservewraphfoo
+#define fooreservewraphfoo
+
+/***
+  This file is part of PulseAudio.
+
+  Copyright 2009 Lennart Poettering
+
+  PulseAudio is free software; you can redistribute it and/or modify
+  it under the terms of the GNU Lesser General Public License as published
+  by the Free Software Foundation; either version 2 of the License,
+  or (at your option) any later version.
+
+  PulseAudio is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with PulseAudio; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+  USA.
+***/
+
+#include <pulsecore/core.h>
+#include <pulsecore/hook-list.h>
+
+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);
+
+#endif
diff --git a/src/modules/reserve.c b/src/modules/reserve.c
new file mode 100644
index 0000000..79ec97a
--- /dev/null
+++ b/src/modules/reserve.c
@@ -0,0 +1,624 @@
+/***
+  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.h"
+
+struct rd_device {
+	int ref;
+
+	char *device_name;
+	char *application_name;
+	char *application_device_name;
+	char *service_name;
+	char *object_path;
+	int32_t priority;
+
+	DBusConnection *connection;
+
+	int owning:1;
+	int registered:1;
+	int filtering:1;
+	int gave_up:1;
+
+	rd_request_cb_t request_cb;
+	void *userdata;
+};
+
+
+#define SERVICE_PREFIX "org.freedesktop.ReserveDevice1."
+#define OBJECT_PREFIX "/org/freedesktop/ReserveDevice1/"
+
+static const char introspection[] =
+	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
+	"<node>"
+	" <interface name=\"org.freedesktop.ReserveDevice1\">"
+	"  <method name=\"RequestRelease\">"
+	"   <arg name=\"priority\" type=\"i\" direction=\"in\"/>"
+	"   <arg name=\"result\" type=\"b\" direction=\"out\"/>"
+	"  </method>"
+	"  <property name=\"Priority\" type=\"i\" access=\"read\"/>"
+	"  <property name=\"ApplicationName\" type=\"s\" access=\"read\"/>"
+	"  <property name=\"ApplicationDeviceName\" type=\"s\" access=\"read\"/>"
+	" </interface>"
+	" <interface name=\"org.freedesktop.DBus.Properties\">"
+	"  <method name=\"Get\">"
+	"   <arg name=\"interface\" direction=\"in\" type=\"s\"/>"
+	"   <arg name=\"property\" direction=\"in\" type=\"s\"/>"
+	"   <arg name=\"value\" direction=\"out\" type=\"v\"/>"
+	"  </method>"
+	" </interface>"
+	" <interface name=\"org.freedesktop.DBus.Introspectable\">"
+	"  <method name=\"Introspect\">"
+	"   <arg name=\"data\" type=\"s\" direction=\"out\"/>"
+	"  </method>"
+	" </interface>"
+	"</node>";
+
+static dbus_bool_t add_variant(
+	DBusMessage *m,
+	int type,
+	const void *data) {
+
+	DBusMessageIter iter, sub;
+	char t[2];
+
+	t[0] = (char) type;
+	t[1] = 0;
+
+	dbus_message_iter_init_append(m, &iter);
+
+	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, t, &sub))
+		return FALSE;
+
+	if (!dbus_message_iter_append_basic(&sub, type, data))
+		return FALSE;
+
+	if (!dbus_message_iter_close_container(&iter, &sub))
+		return FALSE;
+
+	return TRUE;
+}
+
+static DBusHandlerResult object_handler(
+	DBusConnection *c,
+	DBusMessage *m,
+	void *userdata) {
+
+	rd_device *d;
+	DBusError error;
+	DBusMessage *reply = NULL;
+
+	dbus_error_init(&error);
+
+	d = userdata;
+	assert(d->ref >= 1);
+
+	if (dbus_message_is_method_call(
+		    m,
+		    "org.freedesktop.ReserveDevice1",
+		    "RequestRelease")) {
+
+		int32_t priority;
+		dbus_bool_t ret;
+
+		if (!dbus_message_get_args(
+			    m,
+			    &error,
+			    DBUS_TYPE_INT32, &priority,
+			    DBUS_TYPE_INVALID))
+			goto invalid;
+
+		ret = FALSE;
+
+		if (priority > d->priority && d->request_cb) {
+			d->ref++;
+
+			if (d->request_cb(d, 0) > 0) {
+				ret = TRUE;
+				d->gave_up = 1;
+			}
+
+			rd_release(d);
+		}
+
+		if (!(reply = dbus_message_new_method_return(m)))
+			goto oom;
+
+		if (!dbus_message_append_args(
+			    reply,
+			    DBUS_TYPE_BOOLEAN, &ret,
+			    DBUS_TYPE_INVALID))
+			goto oom;
+
+		if (!dbus_connection_send(c, reply, NULL))
+			goto oom;
+
+		dbus_message_unref(reply);
+
+		return DBUS_HANDLER_RESULT_HANDLED;
+
+	} else if (dbus_message_is_method_call(
+			   m,
+			   "org.freedesktop.DBus.Properties",
+			   "Get")) {
+
+		const char *interface, *property;
+
+		if (!dbus_message_get_args(
+			    m,
+			    &error,
+			    DBUS_TYPE_STRING, &interface,
+			    DBUS_TYPE_STRING, &property,
+			    DBUS_TYPE_INVALID))
+			goto invalid;
+
+		if (strcmp(interface, "org.freedesktop.ReserveDevice1") == 0) {
+			const char *empty = "";
+
+			if (strcmp(property, "ApplicationName") == 0 && d->application_name) {
+				if (!(reply = dbus_message_new_method_return(m)))
+					goto oom;
+
+				if (!add_variant(
+					    reply,
+					    DBUS_TYPE_STRING,
+					    d->application_name ? (const char**) &d->application_name : &empty))
+					goto oom;
+
+			} else if (strcmp(property, "ApplicationDeviceName") == 0) {
+				if (!(reply = dbus_message_new_method_return(m)))
+					goto oom;
+
+				if (!add_variant(
+					    reply,
+					    DBUS_TYPE_STRING,
+					    d->application_device_name ? (const char**) &d->application_device_name : &empty))
+					goto oom;
+
+			} else if (strcmp(property, "Priority") == 0) {
+				if (!(reply = dbus_message_new_method_return(m)))
+					goto oom;
+
+				if (!add_variant(
+					    reply,
+					    DBUS_TYPE_INT32,
+					    &d->priority))
+					goto oom;
+			} else {
+				if (!(reply = dbus_message_new_error_printf(
+					      m,
+					      DBUS_ERROR_UNKNOWN_METHOD,
+					      "Unknown property %s",
+					      property)))
+					goto oom;
+			}
+
+			if (!dbus_connection_send(c, reply, NULL))
+				goto oom;
+
+			dbus_message_unref(reply);
+
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+
+	} else if (dbus_message_is_method_call(
+			   m,
+			   "org.freedesktop.DBus.Introspectable",
+			   "Introspect")) {
+			    const char *i = introspection;
+
+		if (!(reply = dbus_message_new_method_return(m)))
+			goto oom;
+
+		if (!dbus_message_append_args(
+			    reply,
+			    DBUS_TYPE_STRING,
+			    &i,
+			    DBUS_TYPE_INVALID))
+			goto oom;
+
+		if (!dbus_connection_send(c, reply, NULL))
+			goto oom;
+
+		dbus_message_unref(reply);
+
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+invalid:
+	if (reply)
+		dbus_message_unref(reply);
+
+	if (!(reply = dbus_message_new_error(
+		      m,
+		      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;
+}
+
+static DBusHandlerResult filter_handler(
+	DBusConnection *c,
+	DBusMessage *m,
+	void *userdata) {
+
+	DBusMessage *reply;
+	rd_device *d;
+	DBusError error;
+
+	dbus_error_init(&error);
+
+	d = userdata;
+
+	if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameLost")) {
+		const char *name;
+
+		if (!dbus_message_get_args(
+			    m,
+			    &error,
+			    DBUS_TYPE_STRING, &name,
+			    DBUS_TYPE_INVALID))
+			goto invalid;
+
+		if (strcmp(name, d->service_name) == 0 && d->owning) {
+			d->owning = 0;
+
+			if (!d->gave_up)  {
+				d->ref++;
+
+				if (d->request_cb)
+					d->request_cb(d, 1);
+				d->gave_up = 1;
+
+				rd_release(d);
+			}
+
+			return DBUS_HANDLER_RESULT_HANDLED;
+		}
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+invalid:
+	if (!(reply = dbus_message_new_error(
+		      m,
+		      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;
+}
+
+
+static const struct DBusObjectPathVTable vtable ={
+	.message_function = object_handler
+};
+
+int rd_acquire(
+	rd_device **_d,
+	DBusConnection *connection,
+	const char *device_name,
+	const char *application_name,
+	int32_t priority,
+	rd_request_cb_t request_cb,
+	DBusError *error) {
+
+	rd_device *d = NULL;
+	int r, k;
+	DBusError _error;
+	DBusMessage *m = NULL, *reply = NULL;
+	dbus_bool_t good;
+
+	if (!error)
+		error = &_error;
+
+	dbus_error_init(error);
+
+	if (!_d)
+		return -EINVAL;
+
+	if (!connection)
+		return -EINVAL;
+
+	if (!device_name)
+		return -EINVAL;
+
+	if (!request_cb && priority != INT32_MAX)
+		return -EINVAL;
+
+	if (!(d = calloc(sizeof(rd_device), 1)))
+		return -ENOMEM;
+
+	d->ref = 1;
+
+	if (!(d->device_name = strdup(device_name))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	if (!(d->application_name = strdup(application_name))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	d->priority = priority;
+	d->connection = dbus_connection_ref(connection);
+	d->request_cb = request_cb;
+
+	if (!(d->service_name = malloc(sizeof(SERVICE_PREFIX) + strlen(device_name)))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+	sprintf(d->service_name, SERVICE_PREFIX "%s", d->device_name);
+
+	if (!(d->object_path = malloc(sizeof(OBJECT_PREFIX) + strlen(device_name)))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+	sprintf(d->object_path, OBJECT_PREFIX "%s", d->device_name);
+
+	if ((k = dbus_bus_request_name(
+		     d->connection,
+		     d->service_name,
+		     DBUS_NAME_FLAG_DO_NOT_QUEUE|
+		     (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0),
+		     error)) < 0) {
+		r = -EIO;
+		goto fail;
+	}
+
+	if (k == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+		goto success;
+
+	if (k != DBUS_REQUEST_NAME_REPLY_EXISTS) {
+		r = -EIO;
+		goto fail;
+	}
+
+	if (priority <= INT32_MIN) {
+		r = -EBUSY;
+		goto fail;
+	}
+
+	if (!(m = dbus_message_new_method_call(
+		      d->service_name,
+		      d->object_path,
+		      "org.freedesktop.ReserveDevice1",
+		      "RequestRelease"))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	if (!dbus_message_append_args(
+		    m,
+		    DBUS_TYPE_INT32, &d->priority,
+		    DBUS_TYPE_INVALID)) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	if (!(reply = dbus_connection_send_with_reply_and_block(
+		      d->connection,
+		      m,
+		      -1,
+		      error))) {
+		r = -EIO;
+		goto fail;
+	}
+
+	if (!dbus_message_get_args(
+		    reply,
+		    error,
+		    DBUS_TYPE_BOOLEAN, &good,
+		    DBUS_TYPE_INVALID)) {
+		r = -EIO;
+		goto fail;
+	}
+
+	if (!good) {
+		r = -EBUSY;
+		goto fail;
+	}
+
+	if ((k = dbus_bus_request_name(
+		     d->connection,
+		     d->service_name,
+		     DBUS_NAME_FLAG_DO_NOT_QUEUE|
+		     (priority < INT32_MAX ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT : 0)|
+		     DBUS_NAME_FLAG_REPLACE_EXISTING,
+		     error)) < 0) {
+		r = -EIO;
+		goto fail;
+	}
+
+	if (k != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		r = -EIO;
+		goto fail;
+	}
+
+success:
+	d->owning = 1;
+
+	if (!(dbus_connection_register_object_path(
+		      d->connection,
+		      d->object_path,
+		      &vtable,
+		      d))) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	d->registered = 1;
+
+	if (!dbus_connection_add_filter(
+		    d->connection,
+		    filter_handler,
+		    d,
+		    NULL)) {
+		r = -ENOMEM;
+		goto fail;
+	}
+
+	d->filtering = 1;
+
+	*_d = d;
+	return 0;
+
+fail:
+	if (m)
+		dbus_message_unref(m);
+
+	if (reply)
+		dbus_message_unref(reply);
+
+	if (&_error == error)
+		dbus_error_free(&_error);
+
+	if (d)
+		rd_release(d);
+
+	return r;
+}
+
+void rd_release(
+	rd_device *d) {
+
+	if (!d)
+		return;
+
+	assert(d->ref > 0);
+
+	if (--d->ref)
+		return;
+
+
+	if (d->filtering)
+		dbus_connection_remove_filter(
+			d->connection,
+			filter_handler,
+			d);
+
+	if (d->registered)
+		dbus_connection_unregister_object_path(
+			d->connection,
+			d->object_path);
+
+	if (d->owning) {
+		DBusError error;
+		dbus_error_init(&error);
+
+		dbus_bus_release_name(
+			d->connection,
+			d->service_name,
+			&error);
+
+		dbus_error_free(&error);
+	}
+
+	free(d->device_name);
+	free(d->application_name);
+	free(d->application_device_name);
+	free(d->service_name);
+	free(d->object_path);
+
+	if (d->connection)
+		dbus_connection_unref(d->connection);
+
+	free(d);
+}
+
+int rd_set_application_device_name(rd_device *d, const char *n) {
+	char *t;
+
+	if (!d)
+		return -EINVAL;
+
+	assert(d->ref > 0);
+
+	if (!(t = strdup(n)))
+		return -ENOMEM;
+
+	free(d->application_device_name);
+	d->application_device_name = t;
+	return 0;
+}
+
+void rd_set_userdata(rd_device *d, void *userdata) {
+
+	if (!d)
+		return;
+
+	assert(d->ref > 0);
+	d->userdata = userdata;
+}
+
+void* rd_get_userdata(rd_device *d) {
+
+	if (!d)
+		return NULL;
+
+	assert(d->ref > 0);
+
+	return d->userdata;
+}
diff --git a/src/modules/reserve.h b/src/modules/reserve.h
new file mode 100644
index 0000000..ceb1ad1
--- /dev/null
+++ b/src/modules/reserve.h
@@ -0,0 +1,68 @@
+#ifndef fooreservehfoo
+#define fooreservehfoo
+
+/***
+  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 rd_device rd_device;
+
+/* Prototype for a function that is called whenever someone else wants
+ * your app to release the device you having locked. A return value <=
+ * 0 denies the request, a positive return value agrees to it. Before
+ * returning your application should close the device in question
+ * completely to make sure the new application may acceess it. */
+typedef int (*rd_request_cb_t)(
+	rd_device *d,
+	int forced);                  /* Non-zero if an application forcibly took the lock away without asking. If this is the case then the return value of this call is ignored. */
+
+/* Try to lock the 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 rd_acquire(
+	rd_device **d,                /* On success a pointer to the newly allocated rd_device object will be filled in here */
+	DBusConnection *connection,
+	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 */
+	rd_request_cb_t request_cb,   /* Will be called whenever someone asks that this device shall be released. May be NULL if priority is INT32_MAX */
+	DBusError *error);            /* If we fail due to a D-Bus related issue the error will be filled in here. May be NULL. */
+
+/* Unlock (if needed) and destroy a rd_device object again */
+void rd_release(rd_device *d);
+
+/* Set the application device name for a rd_device object Returns 0 on
+ * success, a negative errno style return value on error. */
+int rd_set_application_device_name(rd_device *d, const char *name);
+
+/* Attach a userdata pointer to a rd_device */
+void rd_set_userdata(rd_device *d, void *userdata);
+
+/* Query the userdata pointer from a rd_device. Returns NULL if no
+ * userdata was set. */
+void* rd_get_userdata(rd_device *d);
+
+#endif

commit ba3c7668a472672bd86eb06dbbbffcef17722134
Author: Lennart Poettering <lennart at poettering.net>
Date:   Tue Feb 24 06:36:42 2009 +0100

    update reserve.c from upstream git

diff --git a/src/modules/reserve.c b/src/modules/reserve.c
index 79ec97a..9a9591d 100644
--- a/src/modules/reserve.c
+++ b/src/modules/reserve.c
@@ -59,6 +59,8 @@ struct rd_device {
 static const char introspection[] =
 	DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
 	"<node>"
+	" <!-- If you are looking for documentation make sure to check out\n"
+	"      http://git.0pointer.de/?p=reserve.git;a=blob;f=reserve.txt -->\n"
 	" <interface name=\"org.freedesktop.ReserveDevice1\">"
 	"  <method name=\"RequestRelease\">"
 	"   <arg name=\"priority\" type=\"i\" direction=\"in\"/>"
@@ -461,8 +463,17 @@ int rd_acquire(
 	if (!(reply = dbus_connection_send_with_reply_and_block(
 		      d->connection,
 		      m,
-		      -1,
+		      5000, /* 5s */
 		      error))) {
+
+		if (dbus_error_has_name(error, DBUS_ERROR_TIMED_OUT) ||
+		    dbus_error_has_name(error, DBUS_ERROR_UNKNOWN_METHOD) ||
+		    dbus_error_has_name(error, DBUS_ERROR_NO_REPLY)) {
+			/* This must be treated as denied. */
+			r = -EBUSY;
+			goto fail;
+		}
+
 		r = -EIO;
 		goto fail;
 	}

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list