[pulseaudio-commits] [SCM] PulseAudio Sound Server branch, master, updated. v0.9.16-test4-45-g72d2540

Lennart Poettering gitmailer-noreply at 0pointer.de
Fri Aug 14 10:30:48 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  17d57415f5abad5b7c30301227054b4c899bc705 (commit)

- Log -----------------------------------------------------------------
72d2540 protocol-native: log explicitly each time a client triggers a volume change
a1598c7 daemon: reset gids too, not just uids
fecd0dc resampler: round up when estimating input/output sizes
9e21182 thread-mq: never drop queued messages for the main loop
446fb2c asyncmsgq: add pa_asyncmsgq_flush() call
a42c597 memblockq: add pa_memblockq_get_maxrewind() API
b0cabfe shm: bump shm size limit to 1GB
aae7054 pacmd: handle multi word commands in argv[] properly
5ee4069 core: add functions to query max_rewind/max_request values from streams
9a95fe4 core: add assert macros for verifying calling context
-----------------------------------------------------------------------

Summary of changes:
 src/daemon/caps.c               |    8 ++++
 src/pulsecore/asyncmsgq.c       |   36 ++++++++++++++--
 src/pulsecore/asyncmsgq.h       |    2 +
 src/pulsecore/memblockq.c       |    6 +++
 src/pulsecore/memblockq.h       |    3 +
 src/pulsecore/protocol-native.c |   15 +++++-
 src/pulsecore/resampler.c       |    8 +++-
 src/pulsecore/shm.c             |    3 +-
 src/pulsecore/sink-input.c      |   71 +++++++++++++++++++++++++++++--
 src/pulsecore/sink-input.h      |    7 +++
 src/pulsecore/sink.c            |   89 ++++++++++++++++++++++++++++++++-------
 src/pulsecore/sink.h            |    7 +++
 src/pulsecore/source-output.c   |   41 ++++++++++++++++-
 src/pulsecore/source-output.h   |    5 ++
 src/pulsecore/source.c          |   66 +++++++++++++++++++++++++----
 src/pulsecore/source.h          |    4 ++
 src/pulsecore/thread-mq.c       |    7 +++
 src/pulsecore/thread-mq.h       |    8 ++++
 src/utils/pacmd.c               |    2 +-
 19 files changed, 346 insertions(+), 42 deletions(-)

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

commit 9a95fe49c848d2711dcdcf4c407e626e41e4657f
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Aug 13 02:14:19 2009 +0200

    core: add assert macros for verifying calling context
    
    This adds pa_assert_io_context() and pa_assert_ctl_context() in addition
    to a few related macros. When called they will fail when the current execution
    context is not IO resp. not control context. (aka 'thread' context vs.
    'main' context)

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index a5f9635..c783729 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -51,7 +51,7 @@ static void sink_input_free(pa_object *o);
 pa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
     pa_assert(data);
 
-    memset(data, 0, sizeof(*data));
+    pa_zero(*data);
     data->resample_method = PA_RESAMPLER_INVALID;
     data->proplist = pa_proplist_new();
 
@@ -142,6 +142,7 @@ int pa_sink_input_new(
     pa_assert(_i);
     pa_assert(core);
     pa_assert(data);
+    pa_assert_ctl_context();
 
     if (data->client)
         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
@@ -348,6 +349,7 @@ int pa_sink_input_new(
 /* Called from main context */
 static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
     pa_assert(i);
+    pa_assert_ctl_context();
 
     if (!i->sink)
         return;
@@ -362,6 +364,7 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
 static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
     pa_sink_input *ssync;
     pa_assert(i);
+    pa_assert_ctl_context();
 
     if (state == PA_SINK_INPUT_DRAINED)
         state = PA_SINK_INPUT_RUNNING;
@@ -400,7 +403,9 @@ static void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state)
 void pa_sink_input_unlink(pa_sink_input *i) {
     pa_bool_t linked;
     pa_source_output *o, *p =  NULL;
+
     pa_assert(i);
+    pa_assert_ctl_context();
 
     /* See pa_sink_unlink() for a couple of comments how this function
      * works */
@@ -471,6 +476,7 @@ static void sink_input_free(pa_object *o) {
     pa_sink_input* i = PA_SINK_INPUT(o);
 
     pa_assert(i);
+    pa_assert_ctl_context();
     pa_assert(pa_sink_input_refcnt(i) == 0);
 
     if (PA_SINK_INPUT_IS_LINKED(i->state))
@@ -502,7 +508,9 @@ static void sink_input_free(pa_object *o) {
 /* Called from main context */
 void pa_sink_input_put(pa_sink_input *i) {
     pa_sink_input_state_t state;
+
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     pa_assert(i->state == PA_SINK_INPUT_INIT);
 
@@ -538,6 +546,7 @@ void pa_sink_input_put(pa_sink_input *i) {
 /* Called from main context */
 void pa_sink_input_kill(pa_sink_input*i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     i->kill(i);
@@ -548,6 +557,7 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
     pa_usec_t r[2] = { 0, 0 };
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
@@ -569,6 +579,7 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
     size_t ilength;
 
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
     pa_assert(pa_frame_aligned(slength, &i->sink->sample_spec));
     pa_assert(chunk);
@@ -706,8 +717,9 @@ void pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink frames */, p
 
 /* Called from thread context */
 void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
-    pa_sink_input_assert_ref(i);
 
+    pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
     pa_assert(nbytes > 0);
@@ -721,8 +733,9 @@ void pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec *
 void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
     size_t lbq;
     pa_bool_t called = FALSE;
-    pa_sink_input_assert_ref(i);
 
+    pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
 
@@ -792,6 +805,7 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
 /* Called from thread context */
 void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes  /* in the sink's sample spec */) {
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
 
@@ -804,6 +818,7 @@ void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes  /* in the
 /* Called from thread context */
 void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes  /* in the sink's sample spec */) {
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
 
@@ -814,6 +829,7 @@ void pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes  /* in the
 /* Called from thread context */
 pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
 
     if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
         usec = i->sink->fixed_latency;
@@ -830,6 +846,7 @@ pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa
 /* Called from main context */
 pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
         pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
@@ -858,6 +875,7 @@ pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec)
 /* Called from main context */
 pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
         pa_usec_t usec = 0;
@@ -876,6 +894,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
     pa_cvolume v;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(volume);
     pa_assert(pa_cvolume_valid(volume));
@@ -922,6 +941,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
 /* Called from main context */
 pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, pa_bool_t absolute) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     if ((i->sink->flags & PA_SINK_FLAT_VOLUME) && !absolute) {
@@ -939,6 +959,7 @@ pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
     unsigned c;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(v);
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
@@ -959,6 +980,7 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) {
     pa_cvolume _v;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec));
 
@@ -985,8 +1007,8 @@ void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v) {
 
 /* Called from main context */
 void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
-    pa_assert(i);
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     if (!i->muted == !mute)
@@ -1002,6 +1024,7 @@ void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
 /* Called from main context */
 pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     return i->muted;
@@ -1010,6 +1033,7 @@ pa_bool_t pa_sink_input_get_mute(pa_sink_input *i) {
 /* Called from main thread */
 void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     if (p)
         pa_proplist_update(i->proplist, mode, p);
@@ -1023,6 +1047,7 @@ void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_p
 /* Called from main context */
 void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
@@ -1031,6 +1056,7 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b) {
 /* Called from main context */
 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE);
 
@@ -1049,13 +1075,14 @@ int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
 void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
     const char *old;
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     if (!name && !pa_proplist_contains(i->proplist, PA_PROP_MEDIA_NAME))
         return;
 
     old = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME);
 
-    if (old && name && !strcmp(old, name))
+    if (old && name && pa_streq(old, name))
         return;
 
     if (name)
@@ -1072,6 +1099,7 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) {
 /* Called from main context */
 pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     return i->actual_resample_method;
 }
@@ -1079,6 +1107,7 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
 /* Called from main context */
 pa_bool_t pa_sink_input_may_move(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
 
     if (i->flags & PA_SINK_INPUT_DONT_MOVE)
@@ -1095,6 +1124,7 @@ pa_bool_t pa_sink_input_may_move(pa_sink_input *i) {
 /* Called from main context */
 pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_sink_assert_ref(dest);
 
@@ -1123,6 +1153,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
     int r;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(i->sink);
 
@@ -1177,6 +1208,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     pa_resampler *new_resampler;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(!i->sink);
     pa_sink_assert_ref(dest);
@@ -1271,6 +1303,7 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
     int r;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
     pa_assert(i->sink);
     pa_sink_assert_ref(dest);
@@ -1301,7 +1334,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
 /* Called from IO thread context */
 void pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
     pa_bool_t corking, uncorking;
+
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
 
     if (state == i->thread_info.state)
         return;
@@ -1411,6 +1446,7 @@ int pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t
 /* Called from main thread */
 pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
 
     if (i->state == PA_SINK_INPUT_RUNNING || i->state == PA_SINK_INPUT_DRAINED)
         return pa_atomic_load(&i->thread_info.drained) ? PA_SINK_INPUT_DRAINED : PA_SINK_INPUT_RUNNING;
@@ -1421,6 +1457,7 @@ pa_sink_input_state_t pa_sink_input_get_state(pa_sink_input *i) {
 /* Called from IO context */
 pa_bool_t pa_sink_input_safe_to_remove(pa_sink_input *i) {
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
 
     if (PA_SINK_INPUT_IS_LINKED(i->thread_info.state))
         return pa_memblockq_is_empty(i->thread_info.render_memblockq);
@@ -1445,6 +1482,7 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes  /* in our sam
      * rewound. */
 
     pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
 
     nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes);
 
@@ -1511,8 +1549,11 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes  /* in our sam
 /* Called from main context */
 pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(ret);
 
+    /* FIXME: Shouldn't access resampler object from main context! */
+
     pa_silence_memchunk_get(
                 &i->core->silence_cache,
                 i->core->mempool,
@@ -1529,6 +1570,7 @@ void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *
     pa_sink_input_send_event_hook_data hook_data;
 
     pa_sink_input_assert_ref(i);
+    pa_assert_ctl_context();
     pa_assert(event);
 
     if (!i->send_event)
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 98144d4..5ede1ca 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -359,4 +359,7 @@ pa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret);
 /* To be used by sink.c only */
 void pa_sink_input_set_relative_volume(pa_sink_input *i, const pa_cvolume *v);
 
+#define pa_sink_input_assert_io_context(s) \
+    pa_assert(pa_thread_mq_get() || !PA_SINK_INPUT_IS_LINKED((s)->state))
+
 #endif
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 5e9662c..edcf5bd 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -59,7 +59,7 @@ static void sink_free(pa_object *s);
 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
     pa_assert(data);
 
-    memset(data, 0, sizeof(*data));
+    pa_zero(*data);
     data->proplist = pa_proplist_new();
 
     return data;
@@ -177,6 +177,7 @@ pa_sink* pa_sink_new(
     pa_assert(core);
     pa_assert(data);
     pa_assert(data->name);
+    pa_assert_ctl_context();
 
     s = pa_msgobject_new(pa_sink);
 
@@ -360,6 +361,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
     pa_sink_state_t original_state;
 
     pa_assert(s);
+    pa_assert_ctl_context();
 
     if (s->state == state)
         return 0;
@@ -413,6 +415,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
 /* Called from main context */
 void pa_sink_put(pa_sink* s) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     pa_assert(s->state == PA_SINK_INIT);
 
@@ -458,6 +461,7 @@ void pa_sink_unlink(pa_sink* s) {
     pa_sink_input *i, *j = NULL;
 
     pa_assert(s);
+    pa_assert_ctl_context();
 
     /* Please note that pa_sink_unlink() does more than simply
      * reversing pa_sink_put(). It also undoes the registrations
@@ -507,6 +511,7 @@ static void sink_free(pa_object *o) {
     pa_sink_input *i;
 
     pa_assert(s);
+    pa_assert_ctl_context();
     pa_assert(pa_sink_refcnt(s) == 0);
 
     if (PA_SINK_IS_LINKED(s->state))
@@ -550,6 +555,7 @@ static void sink_free(pa_object *o) {
 /* Called from main context */
 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     s->asyncmsgq = q;
 
@@ -560,6 +566,7 @@ void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
 /* Called from main context */
 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     s->rtpoll = p;
 
@@ -570,6 +577,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
 /* Called from main context */
 int pa_sink_update_status(pa_sink*s) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     if (s->state == PA_SINK_SUSPENDED)
@@ -581,6 +589,7 @@ int pa_sink_update_status(pa_sink*s) {
 /* Called from main context */
 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(cause != 0);
 
@@ -609,6 +618,7 @@ pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) {
     uint32_t idx;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     if (!q)
@@ -633,6 +643,7 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
     pa_sink_input *i;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(q);
 
@@ -649,6 +660,8 @@ void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
 /* Called from main context */
 void pa_sink_move_all_fail(pa_queue *q) {
     pa_sink_input *i;
+
+    pa_assert_ctl_context();
     pa_assert(q);
 
     while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
@@ -667,6 +680,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 
     /* If nobody requested this and this is actually no real rewind
@@ -703,6 +717,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns
     size_t mixlength = *length;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(info);
 
     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
@@ -742,6 +757,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *
     unsigned n_unreffed = 0;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(result);
     pa_assert(result->memblock);
     pa_assert(result->length > 0);
@@ -837,6 +853,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
     size_t block_size_max;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
     pa_assert(pa_frame_aligned(length, &s->sample_spec));
     pa_assert(result);
@@ -923,6 +940,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
     size_t length, block_size_max;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
     pa_assert(target);
     pa_assert(target->memblock);
@@ -1006,6 +1024,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
     size_t l, d;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
     pa_assert(target);
     pa_assert(target->memblock);
@@ -1040,6 +1059,7 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
     unsigned n;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
     pa_assert(length > 0);
     pa_assert(pa_frame_aligned(length, &s->sample_spec));
@@ -1131,6 +1151,7 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
     pa_usec_t usec = 0;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     /* The returned value is supposed to be in the time domain of the sound card! */
@@ -1152,6 +1173,7 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
     pa_msgobject *o;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 
     /* The returned value is supposed to be in the time domain of the sound card! */
@@ -1218,6 +1240,7 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
     uint32_t idx;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(new_volume);
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
@@ -1274,6 +1297,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) {
     uint32_t idx;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
 
@@ -1322,6 +1346,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
     pa_bool_t virtual_volume_changed;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
     pa_assert(volume);
     pa_assert(pa_cvolume_valid(volume));
@@ -1363,6 +1388,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
 /* Called from main thread. Only to be called by sink implementor */
 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(volume);
 
     s->soft_volume = *volume;
@@ -1376,6 +1402,8 @@ void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
 /* Called from main thread */
 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_IS_LINKED(s->state));
 
     if (s->refresh_volume || force_refresh) {
         struct pa_cvolume old_virtual_volume = s->virtual_volume;
@@ -1408,6 +1436,8 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo
 /* Called from main thread */
 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_IS_LINKED(s->state));
 
     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
     if (pa_cvolume_equal(&s->virtual_volume, new_volume))
@@ -1427,6 +1457,7 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
     pa_bool_t old_muted;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     old_muted = s->muted;
@@ -1446,6 +1477,8 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_IS_LINKED(s->state));
 
     if (s->refresh_muted || force_refresh) {
         pa_bool_t old_muted = s->muted;
@@ -1472,6 +1505,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
 /* Called from main thread */
 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SINK_IS_LINKED(s->state));
 
     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
 
@@ -1487,6 +1522,7 @@ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
 /* Called from main thread */
 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (p)
         pa_proplist_update(s->proplist, mode, p);
@@ -1500,16 +1536,18 @@ pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist
 }
 
 /* Called from main thread */
+/* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
 void pa_sink_set_description(pa_sink *s, const char *description) {
     const char *old;
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
         return;
 
     old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
 
-    if (old && description && !strcmp(old, description))
+    if (old && description && pa_streq(old, description))
         return;
 
     if (description)
@@ -1536,6 +1574,7 @@ unsigned pa_sink_linked_by(pa_sink *s) {
     unsigned ret;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     ret = pa_idxset_size(s->inputs);
@@ -1554,6 +1593,7 @@ unsigned pa_sink_used_by(pa_sink *s) {
     unsigned ret;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     ret = pa_idxset_size(s->inputs);
@@ -1572,6 +1612,7 @@ unsigned pa_sink_check_suspend(pa_sink *s) {
     uint32_t idx;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!PA_SINK_IS_LINKED(s->state))
         return 0;
@@ -1605,8 +1646,9 @@ static void sync_input_volumes_within_thread(pa_sink *s) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
-    while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
+    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
         if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
             continue;
 
@@ -1942,9 +1984,10 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause)
     int ret = 0;
 
     pa_core_assert_ref(c);
+    pa_assert_ctl_context();
     pa_assert(cause != 0);
 
-    for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
+    PA_IDXSET_FOREACH(sink, c->sinks, idx) {
         int r;
 
         if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
@@ -1957,6 +2000,7 @@ int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause)
 /* Called from main thread */
 void pa_sink_detach(pa_sink *s) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
@@ -1965,6 +2009,7 @@ void pa_sink_detach(pa_sink *s) {
 /* Called from main thread */
 void pa_sink_attach(pa_sink *s) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
@@ -1976,9 +2021,10 @@ void pa_sink_detach_within_thread(pa_sink *s) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 
-    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
         if (i->detach)
             i->detach(i);
 
@@ -1992,9 +2038,10 @@ void pa_sink_attach_within_thread(pa_sink *s) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 
-    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
         if (i->attach)
             i->attach(i);
 
@@ -2005,6 +2052,7 @@ void pa_sink_attach_within_thread(pa_sink *s) {
 /* Called from IO thread */
 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
 
     if (s->thread_info.state == PA_SINK_SUSPENDED)
@@ -2034,6 +2082,7 @@ pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
     pa_usec_t monitor_latency;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
     if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
         return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
@@ -2070,6 +2119,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
     pa_usec_t usec = 0;
 
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SINK_IS_LINKED(s->state));
 
     if (s->state == PA_SINK_SUSPENDED)
@@ -2085,16 +2135,16 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
     if (max_rewind == s->thread_info.max_rewind)
         return;
 
     s->thread_info.max_rewind = max_rewind;
 
-    if (PA_SINK_IS_LINKED(s->thread_info.state)) {
-        while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+    if (PA_SINK_IS_LINKED(s->thread_info.state))
+        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
-    }
 
     if (s->monitor_source)
         pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
@@ -2103,6 +2153,7 @@ void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
 /* Called from main thread */
 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (PA_SINK_IS_LINKED(s->state))
         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
@@ -2115,6 +2166,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
     if (max_request == s->thread_info.max_request)
         return;
@@ -2124,7 +2176,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
         pa_sink_input *i;
 
-        while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
             pa_sink_input_update_max_request(i, s->thread_info.max_request);
     }
 }
@@ -2132,6 +2184,7 @@ void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
 /* Called from main thread */
 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (PA_SINK_IS_LINKED(s->state))
         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
@@ -2145,6 +2198,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) {
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
     if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
         return;
@@ -2156,7 +2210,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) {
         if (s->update_requested_latency)
             s->update_requested_latency(s);
 
-        while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
             if (i->update_sink_requested_latency)
                 i->update_sink_requested_latency(i);
     }
@@ -2165,6 +2219,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s) {
 /* Called from main thread */
 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     /* min_latency == 0:           no limit
      * min_latency anything else:  specified limit
@@ -2199,6 +2254,7 @@ void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_
 /* Called from main thread */
 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
    pa_sink_assert_ref(s);
+   pa_assert_ctl_context();
    pa_assert(min_latency);
    pa_assert(max_latency);
 
@@ -2220,6 +2276,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency,
     void *state = NULL;
 
     pa_sink_assert_ref(s);
+    pa_sink_assert_io_context(s);
 
     pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
     pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
@@ -2236,7 +2293,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency,
     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
         pa_sink_input *i;
 
-        while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
+        PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
             if (i->update_sink_latency_range)
                 i->update_sink_latency_range(i);
     }
@@ -2249,7 +2306,7 @@ void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency,
 /* Called from main thread, before the sink is put */
 void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
     pa_sink_assert_ref(s);
-
+    pa_assert_ctl_context();
     pa_assert(pa_sink_get_state(s) == PA_SINK_INIT);
 
     if (latency < ABSOLUTE_MIN_LATENCY)
@@ -2266,6 +2323,7 @@ void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
 size_t pa_sink_get_max_rewind(pa_sink *s) {
     size_t r;
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!PA_SINK_IS_LINKED(s->state))
         return s->thread_info.max_rewind;
@@ -2279,6 +2337,7 @@ size_t pa_sink_get_max_rewind(pa_sink *s) {
 size_t pa_sink_get_max_request(pa_sink *s) {
     size_t r;
     pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!PA_SINK_IS_LINKED(s->state))
         return s->thread_info.max_request;
@@ -2292,7 +2351,8 @@ size_t pa_sink_get_max_request(pa_sink *s) {
 int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
     pa_device_port *port;
 
-    pa_assert(s);
+    pa_sink_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!s->set_port) {
         pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
@@ -2323,7 +2383,6 @@ int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
     return 0;
 }
 
-/* Called from main context */
 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
     const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
 
diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h
index 7a8cdaf..1303396 100644
--- a/src/pulsecore/sink.h
+++ b/src/pulsecore/sink.h
@@ -42,6 +42,7 @@ typedef struct pa_device_port pa_device_port;
 #include <pulsecore/rtpoll.h>
 #include <pulsecore/card.h>
 #include <pulsecore/queue.h>
+#include <pulsecore/thread-mq.h>
 
 #define PA_MAX_INPUTS_PER_SINK 32
 
@@ -343,4 +344,10 @@ pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
 pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
 void pa_device_port_free(pa_device_port *p);
 
+/* Verify that we called in IO context (aka 'thread context), or that
+ * the sink is not yet set up, i.e. the thread not set up yet. See
+ * pa_assert_io_context() in thread-mq.h for more information. */
+#define pa_sink_assert_io_context(s) \
+    pa_assert(pa_thread_mq_get() || !PA_SINK_IS_LINKED((s)->state))
+
 #endif
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index 4ba25ae..fdc00e1 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -48,7 +48,7 @@ static void source_output_free(pa_object* mo);
 pa_source_output_new_data* pa_source_output_new_data_init(pa_source_output_new_data *data) {
     pa_assert(data);
 
-    memset(data, 0, sizeof(*data));
+    pa_zero(*data);
     data->resample_method = PA_RESAMPLER_INVALID;
     data->proplist = pa_proplist_new();
 
@@ -111,6 +111,7 @@ int pa_source_output_new(
     pa_assert(_o);
     pa_assert(core);
     pa_assert(data);
+    pa_assert_ctl_context();
 
     if (data->client)
         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
@@ -262,6 +263,7 @@ int pa_source_output_new(
 /* Called from main context */
 static void update_n_corked(pa_source_output *o, pa_source_output_state_t state) {
     pa_assert(o);
+    pa_assert_ctl_context();
 
     if (!o->source)
         return;
@@ -275,6 +277,7 @@ static void update_n_corked(pa_source_output *o, pa_source_output_state_t state)
 /* Called from main context */
 static void source_output_set_state(pa_source_output *o, pa_source_output_state_t state) {
     pa_assert(o);
+    pa_assert_ctl_context();
 
     if (o->state == state)
         return;
@@ -294,6 +297,7 @@ static void source_output_set_state(pa_source_output *o, pa_source_output_state_
 void pa_source_output_unlink(pa_source_output*o) {
     pa_bool_t linked;
     pa_assert(o);
+    pa_assert_ctl_context();
 
     /* See pa_sink_unlink() for a couple of comments how this function
      * works */
@@ -346,6 +350,7 @@ static void source_output_free(pa_object* mo) {
     pa_source_output *o = PA_SOURCE_OUTPUT(mo);
 
     pa_assert(o);
+    pa_assert_ctl_context();
     pa_assert(pa_source_output_refcnt(o) == 0);
 
     if (PA_SOURCE_OUTPUT_IS_LINKED(o->state))
@@ -371,7 +376,9 @@ static void source_output_free(pa_object* mo) {
 /* Called from main context */
 void pa_source_output_put(pa_source_output *o) {
     pa_source_output_state_t state;
+
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
 
     pa_assert(o->state == PA_SOURCE_OUTPUT_INIT);
 
@@ -395,6 +402,7 @@ void pa_source_output_put(pa_source_output *o) {
 /* Called from main context */
 void pa_source_output_kill(pa_source_output*o) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
     o->kill(o);
@@ -405,6 +413,7 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o, pa_usec_t *source_la
     pa_usec_t r[2] = { 0, 0 };
 
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
     pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
@@ -424,6 +433,7 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
     size_t limit, mbs = 0;
 
     pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
     pa_assert(chunk);
     pa_assert(pa_frame_aligned(chunk->length, &o->source->sample_spec));
@@ -499,8 +509,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
 
 /* Called from thread context */
 void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in source sample spec */) {
-    pa_source_output_assert_ref(o);
 
+    pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
 
@@ -528,6 +539,7 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so
 /* Called from thread context */
 void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes  /* in the source's sample spec */) {
     pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->thread_info.state));
     pa_assert(pa_frame_aligned(nbytes, &o->source->sample_spec));
 
@@ -538,6 +550,7 @@ void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes  /* i
 /* Called from thread context */
 pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec) {
     pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
 
     if (!(o->source->flags & PA_SOURCE_DYNAMIC_LATENCY))
         usec = o->source->fixed_latency;
@@ -554,6 +567,7 @@ pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output
 /* Called from main context */
 pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
 
     if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
         pa_assert_se(pa_asyncmsgq_send(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
@@ -582,6 +596,7 @@ pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t
 /* Called from main context */
 pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
 
     if (PA_SOURCE_OUTPUT_IS_LINKED(o->state) && o->source) {
         pa_usec_t usec = 0;
@@ -598,6 +613,7 @@ pa_usec_t pa_source_output_get_requested_latency(pa_source_output *o) {
 /* Called from main context */
 void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
     source_output_set_state(o, b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING);
@@ -606,6 +622,7 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
 /* Called from main context */
 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
     pa_return_val_if_fail(o->thread_info.resampler, -PA_ERR_BADSTATE);
 
@@ -623,6 +640,7 @@ int pa_source_output_set_rate(pa_source_output *o, uint32_t rate) {
 /* Called from main context */
 void pa_source_output_set_name(pa_source_output *o, const char *name) {
     const char *old;
+    pa_assert_ctl_context();
     pa_source_output_assert_ref(o);
 
     if (!name && !pa_proplist_contains(o->proplist, PA_PROP_MEDIA_NAME))
@@ -647,11 +665,12 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) {
 /* Called from main thread */
 void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode, pa_proplist *p) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
 
     if (p)
         pa_proplist_update(o->proplist, mode, p);
 
-    if (PA_SINK_IS_LINKED(o->state)) {
+    if (PA_SOURCE_OUTPUT_IS_LINKED(o->state)) {
         pa_hook_fire(&o->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PROPLIST_CHANGED], o);
         pa_subscription_post(o->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, o->index);
     }
@@ -660,6 +679,7 @@ void pa_source_output_update_proplist(pa_source_output *o, pa_update_mode_t mode
 /* Called from main context */
 pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
 
     return o->actual_resample_method;
 }
@@ -667,6 +687,7 @@ pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) {
 /* Called from main context */
 pa_bool_t pa_source_output_may_move(pa_source_output *o) {
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
 
     if (o->flags & PA_SOURCE_OUTPUT_DONT_MOVE)
@@ -708,6 +729,7 @@ int pa_source_output_start_move(pa_source_output *o) {
     int r;
 
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
     pa_assert(o->source);
 
@@ -739,6 +761,7 @@ int pa_source_output_finish_move(pa_source_output *o, pa_source *dest, pa_bool_t
     pa_resampler *new_resampler;
 
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
     pa_assert(!o->source);
     pa_source_assert_ref(dest);
@@ -820,6 +843,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
     int r;
 
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(o->state));
     pa_assert(o->source);
     pa_source_assert_ref(dest);
@@ -850,6 +874,7 @@ int pa_source_output_move_to(pa_source_output *o, pa_source *dest, pa_bool_t sav
 /* Called from IO thread context */
 void pa_source_output_set_state_within_thread(pa_source_output *o, pa_source_output_state_t state) {
     pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
 
     if (state == o->thread_info.state)
         return;
@@ -906,11 +931,13 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
     return -PA_ERR_NOTIMPLEMENTED;
 }
 
+/* Called from main context */
 void pa_source_output_send_event(pa_source_output *o, const char *event, pa_proplist *data) {
     pa_proplist *pl = NULL;
     pa_source_output_send_event_hook_data hook_data;
 
     pa_source_output_assert_ref(o);
+    pa_assert_ctl_context();
     pa_assert(event);
 
     if (!o->send_event)
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 9824e16..7b32c86 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -277,4 +277,7 @@ int pa_source_output_process_msg(pa_msgobject *mo, int code, void *userdata, int
 
 pa_usec_t pa_source_output_set_requested_latency_within_thread(pa_source_output *o, pa_usec_t usec);
 
+#define pa_source_output_assert_io_context(s) \
+    pa_assert(pa_thread_mq_get() || !PA_SOURCE_OUTPUT_IS_LINKED((s)->state))
+
 #endif
diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c
index b8af148..97a20b9 100644
--- a/src/pulsecore/source.c
+++ b/src/pulsecore/source.c
@@ -33,6 +33,7 @@
 #include <pulse/timeval.h>
 #include <pulse/util.h>
 
+#include <pulsecore/core-util.h>
 #include <pulsecore/source-output.h>
 #include <pulsecore/namereg.h>
 #include <pulsecore/core-subscribe.h>
@@ -52,7 +53,7 @@ static void source_free(pa_object *o);
 pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data) {
     pa_assert(data);
 
-    memset(data, 0, sizeof(*data));
+    pa_zero(*data);
     data->proplist = pa_proplist_new();
 
     return data;
@@ -145,6 +146,7 @@ pa_source* pa_source_new(
     pa_assert(core);
     pa_assert(data);
     pa_assert(data->name);
+    pa_assert_ctl_context();
 
     s = pa_msgobject_new(pa_source);
 
@@ -297,6 +299,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
     pa_source_state_t original_state;
 
     pa_assert(s);
+    pa_assert_ctl_context();
 
     if (s->state == state)
         return 0;
@@ -348,6 +351,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
 /* Called from main context */
 void pa_source_put(pa_source *s) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     pa_assert(s->state == PA_SOURCE_INIT);
 
@@ -382,6 +386,7 @@ void pa_source_unlink(pa_source *s) {
     pa_source_output *o, *j = NULL;
 
     pa_assert(s);
+    pa_assert_ctl_context();
 
     /* See pa_sink_unlink() for a couple of comments how this function
      * works. */
@@ -423,6 +428,7 @@ static void source_free(pa_object *o) {
     pa_source *s = PA_SOURCE(o);
 
     pa_assert(s);
+    pa_assert_ctl_context();
     pa_assert(pa_source_refcnt(s) == 0);
 
     if (PA_SOURCE_IS_LINKED(s->state))
@@ -460,6 +466,7 @@ static void source_free(pa_object *o) {
 
 /* Called from main context */
 void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
+    pa_assert_ctl_context();
     pa_source_assert_ref(s);
 
     s->asyncmsgq = q;
@@ -467,6 +474,7 @@ void pa_source_set_asyncmsgq(pa_source *s, pa_asyncmsgq *q) {
 
 /* Called from main context */
 void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
+    pa_assert_ctl_context();
     pa_source_assert_ref(s);
 
     s->rtpoll = p;
@@ -475,6 +483,7 @@ void pa_source_set_rtpoll(pa_source *s, pa_rtpoll *p) {
 /* Called from main context */
 int pa_source_update_status(pa_source*s) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (s->state == PA_SOURCE_SUSPENDED)
@@ -486,6 +495,7 @@ int pa_source_update_status(pa_source*s) {
 /* Called from main context */
 int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
     pa_assert(cause != 0);
 
@@ -513,6 +523,7 @@ int pa_source_sync_suspend(pa_source *s) {
     pa_sink_state_t state;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
     pa_assert(s->monitor_of);
 
@@ -532,6 +543,7 @@ pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
     uint32_t idx;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (!q)
@@ -556,6 +568,7 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
     pa_source_output *o;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
     pa_assert(q);
 
@@ -572,6 +585,8 @@ void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save) {
 /* Called from main context */
 void pa_source_move_all_fail(pa_queue *q) {
     pa_source_output *o;
+
+    pa_assert_ctl_context();
     pa_assert(q);
 
     while ((o = PA_SOURCE_OUTPUT(pa_queue_pop(q)))) {
@@ -590,6 +605,7 @@ void pa_source_process_rewind(pa_source *s, size_t nbytes) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
 
     if (nbytes <= 0)
@@ -612,6 +628,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
     pa_assert(chunk);
 
@@ -651,6 +668,7 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) {
 /* Called from IO thread context */
 void pa_source_post_direct(pa_source*s, pa_source_output *o, const pa_memchunk *chunk) {
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
     pa_source_output_assert_ref(o);
     pa_assert(o->thread_info.direct_on_input);
@@ -682,6 +700,7 @@ pa_usec_t pa_source_get_latency(pa_source *s) {
     pa_usec_t usec;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (s->state == PA_SOURCE_SUSPENDED)
@@ -701,6 +720,7 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
     pa_msgobject *o;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
 
     /* The returned value is supposed to be in the time domain of the sound card! */
@@ -727,6 +747,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save
     pa_bool_t virtual_volume_changed;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
     pa_assert(volume);
     pa_assert(pa_cvolume_valid(volume));
@@ -752,6 +773,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save
 /* Called from main thread. Only to be called by source implementor */
 void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(volume);
 
     if (PA_SOURCE_IS_LINKED(s->state))
@@ -763,6 +785,7 @@ void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume) {
 /* Called from main thread */
 const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (s->refresh_volume || force_refresh) {
@@ -785,6 +808,8 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
 /* Called from main thread */
 void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     /* The source implementor may call this if the volume changed to make sure everyone is notified */
 
@@ -802,6 +827,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
     pa_bool_t old_muted;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     old_muted = s->muted;
@@ -820,6 +846,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
 /* Called from main thread */
 pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (s->refresh_muted || force_refresh) {
@@ -846,6 +873,8 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
 /* Called from main thread */
 void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
+    pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     /* The source implementor may call this if the mute state changed to make sure everyone is notified */
 
@@ -861,6 +890,7 @@ void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
 /* Called from main thread */
 pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (p)
         pa_proplist_update(s->proplist, mode, p);
@@ -874,16 +904,18 @@ pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_prop
 }
 
 /* Called from main thread */
+/* FIXME -- this should be dropped and be merged into pa_source_update_proplist() */
 void pa_source_set_description(pa_source *s, const char *description) {
     const char *old;
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
         return;
 
     old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
 
-    if (old && description && !strcmp(old, description))
+    if (old && description && pa_streq(old, description))
         return;
 
     if (description)
@@ -901,6 +933,7 @@ void pa_source_set_description(pa_source *s, const char *description) {
 unsigned pa_source_linked_by(pa_source *s) {
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
+    pa_assert_ctl_context();
 
     return pa_idxset_size(s->outputs);
 }
@@ -911,6 +944,7 @@ unsigned pa_source_used_by(pa_source *s) {
 
     pa_source_assert_ref(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
+    pa_assert_ctl_context();
 
     ret = pa_idxset_size(s->outputs);
     pa_assert(ret >= s->n_corked);
@@ -925,6 +959,7 @@ unsigned pa_source_check_suspend(pa_source *s) {
     uint32_t idx;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (!PA_SOURCE_IS_LINKED(s->state))
         return 0;
@@ -1120,6 +1155,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
     int ret = 0;
 
     pa_core_assert_ref(c);
+    pa_assert_ctl_context();
     pa_assert(cause != 0);
 
     for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
@@ -1138,6 +1174,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t caus
 /* Called from main thread */
 void pa_source_detach(pa_source *s) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_DETACH, NULL, 0, NULL) == 0);
@@ -1146,6 +1183,7 @@ void pa_source_detach(pa_source *s) {
 /* Called from main thread */
 void pa_source_attach(pa_source *s) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
@@ -1157,9 +1195,10 @@ void pa_source_detach_within_thread(pa_source *s) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
 
-    while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+    PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
         if (o->detach)
             o->detach(o);
 }
@@ -1170,9 +1209,10 @@ void pa_source_attach_within_thread(pa_source *s) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
     pa_assert(PA_SOURCE_IS_LINKED(s->thread_info.state));
 
-    while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+    PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
         if (o->attach)
             o->attach(o);
 }
@@ -1184,6 +1224,7 @@ pa_usec_t pa_source_get_requested_latency_within_thread(pa_source *s) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
 
     if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
         return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
@@ -1214,6 +1255,7 @@ pa_usec_t pa_source_get_requested_latency(pa_source *s) {
     pa_usec_t usec = 0;
 
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
     pa_assert(PA_SOURCE_IS_LINKED(s->state));
 
     if (s->state == PA_SOURCE_SUSPENDED)
@@ -1230,21 +1272,22 @@ void pa_source_set_max_rewind_within_thread(pa_source *s, size_t max_rewind) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
 
     if (max_rewind == s->thread_info.max_rewind)
         return;
 
     s->thread_info.max_rewind = max_rewind;
 
-    if (PA_SOURCE_IS_LINKED(s->thread_info.state)) {
-        while ((o = pa_hashmap_iterate(s->thread_info.outputs, &state, NULL)))
+    if (PA_SOURCE_IS_LINKED(s->thread_info.state))
+        PA_HASHMAP_FOREACH(o, s->thread_info.outputs, state)
             pa_source_output_update_max_rewind(o, s->thread_info.max_rewind);
-    }
 }
 
 /* Called from main thread */
 void pa_source_set_max_rewind(pa_source *s, size_t max_rewind) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     if (PA_SOURCE_IS_LINKED(s->state))
         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
@@ -1258,6 +1301,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) {
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
 
     if (!(s->flags & PA_SOURCE_DYNAMIC_LATENCY))
         return;
@@ -1281,6 +1325,7 @@ void pa_source_invalidate_requested_latency(pa_source *s) {
 /* Called from main thread */
 void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t max_latency) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     /* min_latency == 0:           no limit
      * min_latency anything else:  specified limit
@@ -1315,6 +1360,7 @@ void pa_source_set_latency_range(pa_source *s, pa_usec_t min_latency, pa_usec_t
 /* Called from main thread */
 void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
    pa_source_assert_ref(s);
+   pa_assert_ctl_context();
    pa_assert(min_latency);
    pa_assert(max_latency);
 
@@ -1336,6 +1382,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten
     void *state = NULL;
 
     pa_source_assert_ref(s);
+    pa_source_assert_io_context(s);
 
     pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
     pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
@@ -1364,6 +1411,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten
 /* Called from main thread, before the source is put */
 void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
     pa_source_assert_ref(s);
+    pa_assert_ctl_context();
 
     pa_assert(pa_source_get_state(s) == PA_SOURCE_INIT);
 
@@ -1379,6 +1427,7 @@ void pa_source_set_fixed_latency(pa_source *s, pa_usec_t latency) {
 /* Called from main thread */
 size_t pa_source_get_max_rewind(pa_source *s) {
     size_t r;
+    pa_assert_ctl_context();
     pa_source_assert_ref(s);
 
     if (!PA_SOURCE_IS_LINKED(s->state))
@@ -1394,9 +1443,10 @@ int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
     pa_device_port *port;
 
     pa_assert(s);
+    pa_assert_ctl_context();
 
     if (!s->set_port) {
-        pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
+        pa_log_debug("set_port() operation not implemented for source %u \"%s\"", s->index, s->name);
         return -PA_ERR_NOTIMPLEMENTED;
     }
 
diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h
index d22e7ca..001122b 100644
--- a/src/pulsecore/source.h
+++ b/src/pulsecore/source.h
@@ -43,6 +43,7 @@ typedef struct pa_source pa_source;
 #include <pulsecore/source-output.h>
 #include <pulsecore/card.h>
 #include <pulsecore/queue.h>
+#include <pulsecore/thread-mq.h>
 
 #define PA_MAX_OUTPUTS_PER_SOURCE 32
 
@@ -295,4 +296,7 @@ void pa_source_set_latency_range_within_thread(pa_source *s, pa_usec_t min_laten
 void pa_source_invalidate_requested_latency(pa_source *s);
 pa_usec_t pa_source_get_latency_within_thread(pa_source *s);
 
+#define pa_source_assert_io_context(s) \
+    pa_assert(pa_thread_mq_get() || !PA_SOURCE_IS_LINKED((s)->state))
+
 #endif
diff --git a/src/pulsecore/thread-mq.h b/src/pulsecore/thread-mq.h
index 3b5e0e7..96839d2 100644
--- a/src/pulsecore/thread-mq.h
+++ b/src/pulsecore/thread-mq.h
@@ -45,4 +45,12 @@ void pa_thread_mq_install(pa_thread_mq *q);
 /* Return the pa_thread_mq object that is set for the current thread */
 pa_thread_mq *pa_thread_mq_get(void);
 
+/* Verify that we are in control context (aka 'main context'). */
+#define pa_assert_ctl_context(s) \
+    pa_assert(!pa_thread_mq_get())
+
+/* Verify that we are in IO context (aka 'thread context'). */
+#define pa_assert_io_context(s) \
+    pa_assert(pa_thread_mq_get())
+
 #endif

commit 5ee4069e9e68f81a71d208bb720d0c6bc6112fdc
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu Aug 13 02:17:24 2009 +0200

    core: add functions to query max_rewind/max_request values from streams

diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index c783729..1f67d0f 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -803,6 +803,25 @@ void pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sam
 }
 
 /* Called from thread context */
+size_t pa_sink_input_get_max_rewind(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
+
+    return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_rewind) : i->sink->thread_info.max_rewind;
+}
+
+/* Called from thread context */
+size_t pa_sink_input_get_max_request(pa_sink_input *i) {
+    pa_sink_input_assert_ref(i);
+    pa_sink_input_assert_io_context(i);
+
+    /* We're not verifying the status here, to allow this to be called
+     * in the state change handler between _INIT and _RUNNING */
+
+    return i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_request) : i->sink->thread_info.max_request;
+}
+
+/* Called from thread context */
 void pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes  /* in the sink's sample spec */) {
     pa_sink_input_assert_ref(i);
     pa_sink_input_assert_io_context(i);
diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h
index 5ede1ca..cd424e8 100644
--- a/src/pulsecore/sink-input.h
+++ b/src/pulsecore/sink-input.h
@@ -303,6 +303,10 @@ void pa_sink_input_cork(pa_sink_input *i, pa_bool_t b);
 
 int pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate);
 
+/* This returns the sink's fields converted into out sample type */
+size_t pa_sink_input_get_max_rewind(pa_sink_input *i);
+size_t pa_sink_input_get_max_request(pa_sink_input *i);
+
 /* Callable by everyone from main thread*/
 
 /* External code may request disconnection with this function */
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index fdc00e1..5d79dbb 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -537,6 +537,14 @@ void pa_source_output_process_rewind(pa_source_output *o, size_t nbytes /* in so
 }
 
 /* Called from thread context */
+size_t pa_source_output_get_max_rewind(pa_source_output *o) {
+    pa_source_output_assert_ref(o);
+    pa_source_output_assert_io_context(o);
+
+    return o->thread_info.resampler ? pa_resampler_request(o->thread_info.resampler, o->source->thread_info.max_rewind) : o->source->thread_info.max_rewind;
+}
+
+/* Called from thread context */
 void pa_source_output_update_max_rewind(pa_source_output *o, size_t nbytes  /* in the source's sample spec */) {
     pa_source_output_assert_ref(o);
     pa_source_output_assert_io_context(o);
diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h
index 7b32c86..4bf88ca 100644
--- a/src/pulsecore/source-output.h
+++ b/src/pulsecore/source-output.h
@@ -238,6 +238,8 @@ void pa_source_output_cork(pa_source_output *o, pa_bool_t b);
 
 int pa_source_output_set_rate(pa_source_output *o, uint32_t rate);
 
+size_t pa_source_output_get_max_rewind(pa_source_output *o);
+
 /* Callable by everyone */
 
 /* External code may request disconnection with this funcion */

commit aae7054b1c442e62cc1154d15a4b7a569d60d8f4
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:12:36 2009 +0200

    pacmd: handle multi word commands in argv[] properly

diff --git a/src/utils/pacmd.c b/src/utils/pacmd.c
index e4d054b..5ef57e3 100644
--- a/src/utils/pacmd.c
+++ b/src/utils/pacmd.c
@@ -116,7 +116,7 @@ int main(int argc, char*argv[]) {
             size_t k;
 
             k = PA_MIN(sizeof(ibuf) - ibuf_length, strlen(argv[i]));
-            memcpy(ibuf + ibuf_length, argv[1], k);
+            memcpy(ibuf + ibuf_length, argv[i], k);
             ibuf_length += k;
 
             if (ibuf_length < sizeof(ibuf)) {

commit b0cabfe16b5e44ec44828ad342ae5a48dedcc6e6
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:14:35 2009 +0200

    shm: bump shm size limit to 1GB

diff --git a/src/pulsecore/shm.c b/src/pulsecore/shm.c
index 6e42842..fbf777a 100644
--- a/src/pulsecore/shm.c
+++ b/src/pulsecore/shm.c
@@ -60,7 +60,8 @@
 #define MADV_REMOVE 9
 #endif
 
-#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*64))
+/* 1 GiB at max */
+#define MAX_SHM_SIZE (PA_ALIGN(1024*1024*1024))
 
 #ifdef __linux__
 /* On Linux we know that the shared memory blocks are files in

commit a42c597f0aef863ee38065c52fbe60d382f9d5e8
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:16:28 2009 +0200

    memblockq: add pa_memblockq_get_maxrewind() API

diff --git a/src/pulsecore/memblockq.c b/src/pulsecore/memblockq.c
index 77f9efc..32758be 100644
--- a/src/pulsecore/memblockq.c
+++ b/src/pulsecore/memblockq.c
@@ -692,6 +692,12 @@ size_t pa_memblockq_get_minreq(pa_memblockq *bq) {
     return bq->minreq;
 }
 
+size_t pa_memblockq_get_maxrewind(pa_memblockq *bq) {
+    pa_assert(bq);
+
+    return bq->maxrewind;
+}
+
 int64_t pa_memblockq_get_read_index(pa_memblockq *bq) {
     pa_assert(bq);
 
diff --git a/src/pulsecore/memblockq.h b/src/pulsecore/memblockq.h
index 146d261..587c364 100644
--- a/src/pulsecore/memblockq.h
+++ b/src/pulsecore/memblockq.h
@@ -141,6 +141,9 @@ size_t pa_memblockq_get_prebuf(pa_memblockq *bq);
 /* Returns the minimal request value */
 size_t pa_memblockq_get_minreq(pa_memblockq *bq);
 
+/* Returns the maximal rewind value */
+size_t pa_memblockq_get_maxrewind(pa_memblockq *bq);
+
 /* Return the base unit in bytes */
 size_t pa_memblockq_get_base(pa_memblockq *bq);
 

commit 446fb2c9fea4f9c3f268868547f5f11c287ecba0
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:17:48 2009 +0200

    asyncmsgq: add pa_asyncmsgq_flush() call

diff --git a/src/pulsecore/asyncmsgq.c b/src/pulsecore/asyncmsgq.c
index 083d9de..3672140 100644
--- a/src/pulsecore/asyncmsgq.c
+++ b/src/pulsecore/asyncmsgq.c
@@ -26,14 +26,16 @@
 #include <unistd.h>
 #include <errno.h>
 
+#include <pulse/xmalloc.h>
+
 #include <pulsecore/atomic.h>
+#include <pulsecore/macro.h>
 #include <pulsecore/log.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/semaphore.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/core-util.h>
 #include <pulsecore/flist.h>
-#include <pulse/xmalloc.h>
 
 #include "asyncmsgq.h"
 
@@ -76,7 +78,7 @@ static void asyncmsgq_free(pa_asyncmsgq *a) {
     struct asyncmsgq_item *i;
     pa_assert(a);
 
-    while ((i = pa_asyncq_pop(a->asyncq, 0))) {
+    while ((i = pa_asyncq_pop(a->asyncq, FALSE))) {
 
         pa_assert(!i->semaphore);
 
@@ -246,7 +248,7 @@ int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code) {
         pa_memchunk chunk;
         int ret;
 
-        if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, 1) < 0)
+        if (pa_asyncmsgq_get(a, &o, &c, &data, &offset, &chunk, TRUE) < 0)
             return -1;
 
         ret = pa_asyncmsgq_dispatch(o, c, data, offset, &chunk);
@@ -269,7 +271,7 @@ int pa_asyncmsgq_process_one(pa_asyncmsgq *a) {
 
     pa_assert(PA_REFCNT_VALUE(a) > 0);
 
-    if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, 0) < 0)
+    if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0)
         return 0;
 
     pa_asyncmsgq_ref(a);
@@ -323,3 +325,29 @@ int pa_asyncmsgq_dispatch(pa_msgobject *object, int code, void *userdata, int64_
 
     return 0;
 }
+
+void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run) {
+    pa_assert(PA_REFCNT_VALUE(a) > 0);
+
+    for (;;) {
+        pa_msgobject *object;
+        int code;
+        void *data;
+        int64_t offset;
+        pa_memchunk chunk;
+        int ret;
+
+        if (pa_asyncmsgq_get(a, &object, &code, &data, &offset, &chunk, FALSE) < 0)
+            return;
+
+        if (!run) {
+            pa_asyncmsgq_done(a, -1);
+            continue;
+        }
+
+        pa_asyncmsgq_ref(a);
+        ret = pa_asyncmsgq_dispatch(object, code, data, offset, &chunk);
+        pa_asyncmsgq_done(a, ret);
+        pa_asyncmsgq_unref(a);
+    }
+}
diff --git a/src/pulsecore/asyncmsgq.h b/src/pulsecore/asyncmsgq.h
index 1f38207..26f528f 100644
--- a/src/pulsecore/asyncmsgq.h
+++ b/src/pulsecore/asyncmsgq.h
@@ -66,6 +66,8 @@ void pa_asyncmsgq_done(pa_asyncmsgq *q, int ret);
 int pa_asyncmsgq_wait_for(pa_asyncmsgq *a, int code);
 int pa_asyncmsgq_process_one(pa_asyncmsgq *a);
 
+void pa_asyncmsgq_flush(pa_asyncmsgq *a, pa_bool_t run);
+
 /* For the reading side */
 int pa_asyncmsgq_read_fd(pa_asyncmsgq *q);
 int pa_asyncmsgq_read_before_poll(pa_asyncmsgq *a);

commit 9e21182e018db8755dea6368eed93a1a2b93f6f7
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:18:23 2009 +0200

    thread-mq: never drop queued messages for the main loop
    
    Previously we might have dropped messages from IO trheads to the main
    thread. This tuend out to be problematic since this cause SHM release
    messages to be lost. More visibly however this could cause playback
    freezing when moving streams between sinks and removing the old sink
    right away.

diff --git a/src/pulsecore/thread-mq.c b/src/pulsecore/thread-mq.c
index 34f92a7..ec67ae8 100644
--- a/src/pulsecore/thread-mq.c
+++ b/src/pulsecore/thread-mq.c
@@ -104,6 +104,13 @@ void pa_thread_mq_init(pa_thread_mq *q, pa_mainloop_api *mainloop, pa_rtpoll *rt
 void pa_thread_mq_done(pa_thread_mq *q) {
     pa_assert(q);
 
+    /* Since we are called from main context we can be sure that the
+     * inq is empty. However, the outq might still contain messages
+     * for the main loop, which we need to dispatch (e.g. release
+     * msgs, other stuff). Hence do so. */
+
+    pa_asyncmsgq_flush(q->outq, TRUE);
+
     q->mainloop->io_free(q->read_event);
     q->mainloop->io_free(q->write_event);
     q->read_event = q->write_event = NULL;

commit fecd0dc801b0f4c9a929fb7ef00f4bd7f0e3d06c
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 04:21:09 2009 +0200

    resampler: round up when estimating input/output sizes

diff --git a/src/pulsecore/resampler.c b/src/pulsecore/resampler.c
index 17fb848..59e0a0c 100644
--- a/src/pulsecore/resampler.c
+++ b/src/pulsecore/resampler.c
@@ -347,13 +347,17 @@ void pa_resampler_set_output_rate(pa_resampler *r, uint32_t rate) {
 size_t pa_resampler_request(pa_resampler *r, size_t out_length) {
     pa_assert(r);
 
-    return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz;
+    /* Let's round up here */
+
+    return (((((out_length + r->o_fz-1) / r->o_fz) * r->i_ss.rate) + r->o_ss.rate-1) / r->o_ss.rate) * r->i_fz;
 }
 
 size_t pa_resampler_result(pa_resampler *r, size_t in_length) {
     pa_assert(r);
 
-    return (((in_length / r->i_fz)*r->o_ss.rate)/r->i_ss.rate) * r->o_fz;
+    /* Let's round up here */
+
+    return (((((in_length + r->i_fz-1) / r->i_fz) * r->o_ss.rate) + r->i_ss.rate-1) / r->i_ss.rate) * r->o_fz;
 }
 
 size_t pa_resampler_max_block_size(pa_resampler *r) {

commit a1598c742e999cc96a9ccf743c2eb6af8c444c73
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 19:28:18 2009 +0200

    daemon: reset gids too, not just uids

diff --git a/src/daemon/caps.c b/src/daemon/caps.c
index 69e58cc..76b62e0 100644
--- a/src/daemon/caps.c
+++ b/src/daemon/caps.c
@@ -57,21 +57,29 @@ void pa_drop_root(void) {
 
 #ifdef HAVE_GETUID
     uid_t uid;
+    gid_t gid;
 
     pa_log_debug(_("Cleaning up privileges."));
     uid = getuid();
+    gid = getgid();
 
 #if defined(HAVE_SETRESUID)
     pa_assert_se(setresuid(uid, uid, uid) >= 0);
+    pa_assert_se(setresgid(gid, gid, gid) >= 0);
 #elif defined(HAVE_SETREUID)
     pa_assert_se(setreuid(uid, uid) >= 0);
+    pa_assert_se(setregid(gid, gid) >= 0);
 #else
     pa_assert_se(setuid(uid) >= 0);
     pa_assert_se(seteuid(uid) >= 0);
+    pa_assert_se(setgid(gid) >= 0);
+    pa_assert_se(setegid(gid) >= 0);
 #endif
 
     pa_assert_se(getuid() == uid);
     pa_assert_se(geteuid() == uid);
+    pa_assert_se(getgid() == gid);
+    pa_assert_se(getegid() == gid);
 #endif
 
 #ifdef HAVE_SYS_PRCTL_H

commit 72d2540e8dc47e101ac9d5ae24eee1b95e8dbcfa
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri Aug 14 19:31:05 2009 +0200

    protocol-native: log explicitly each time a client triggers a volume change

diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index 9a37c56..0337220 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -3323,6 +3323,7 @@ static void command_set_volume(
     pa_source *source = NULL;
     pa_sink_input *si = NULL;
     const char *name = NULL;
+    const char *client_name;
 
     pa_native_connection_assert_ref(c);
     pa_assert(t);
@@ -3369,12 +3370,20 @@ static void command_set_volume(
 
     CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
 
-    if (sink)
+    client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY));
+
+    if (sink) {
+        pa_log("Client %s changes volume of sink %s.", client_name, sink->name);
         pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE);
-    else if (source)
+    } else if (source) {
+        pa_log("Client %s changes volume of sink %s.", client_name, source->name);
         pa_source_set_volume(source, &volume, TRUE);
-    else if (si)
+    } else if (si) {
+        pa_log("Client %s changes volume of sink %s.",
+                     client_name,
+                     pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME)));
         pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
+    }
 
     pa_pstream_send_simple_ack(c->pstream, tag);
 }

-- 
hooks/post-receive
PulseAudio Sound Server



More information about the pulseaudio-commits mailing list