]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/sink.c
core: add assert macros for verifying calling context
[pulseaudio] / src / pulsecore / sink.c
index 4779229332d3b3bb3b97678c1cfe83d87f915c8b..edcf5bddb1fdb482998db76d32172374a5c66b4e 100644 (file)
@@ -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,10 +177,12 @@ 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);
 
     if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
+        pa_log_debug("Failed to register name %s.", data->name);
         pa_xfree(s);
         return NULL;
     }
@@ -359,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;
@@ -412,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);
 
@@ -457,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
@@ -506,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))
@@ -549,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;
 
@@ -559,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;
 
@@ -569,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)
@@ -580,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);
 
@@ -608,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)
@@ -632,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);
 
@@ -648,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)))) {
@@ -664,11 +678,15 @@ void pa_sink_move_all_fail(pa_queue *q) {
 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
     pa_sink_input *i;
     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
-     * then we can short cut this */
+     * then we can short cut this. Please note that this means that
+     * not all rewind requests triggered upstream will always be
+     * translated in actual requests! */
     if (!s->thread_info.rewind_requested && nbytes <= 0)
         return;
 
@@ -681,7 +699,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
     if (nbytes > 0)
         pa_log_debug("Processing rewind...");
 
-    while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
+    PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
         pa_sink_input_assert_ref(i);
         pa_sink_input_process_rewind(i, nbytes);
     }
@@ -699,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) {
@@ -738,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);
@@ -833,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);
@@ -919,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);
@@ -1002,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);
@@ -1036,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));
@@ -1127,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! */
@@ -1148,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! */
@@ -1214,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);
@@ -1270,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);
 
@@ -1318,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));
@@ -1359,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;
@@ -1372,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;
@@ -1385,6 +1417,12 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo
 
             s->reference_volume = s->virtual_volume;
 
+            /* Something got changed in the hardware. It probably
+             * makes sense to save changed hw settings given that hw
+             * volume changes not triggered by PA are almost certainly
+             * done by the user. */
+            s->save_volume = TRUE;
+
             if (s->flags & PA_SINK_FLAT_VOLUME)
                 pa_sink_propagate_flat_volume(s);
 
@@ -1396,17 +1434,17 @@ 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_bool_t save) {
+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)) {
-        s->save_volume = s->save_volume || save;
+    if (pa_cvolume_equal(&s->virtual_volume, new_volume))
         return;
-    }
 
     s->reference_volume = s->virtual_volume = *new_volume;
-    s->save_volume = save;
+    s->save_volume = TRUE;
 
     if (s->flags & PA_SINK_FLAT_VOLUME)
         pa_sink_propagate_flat_volume(s);
@@ -1419,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;
@@ -1438,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;
@@ -1448,6 +1489,8 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
 
         if (old_muted != s->muted) {
+            s->save_muted = TRUE;
+
             pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 
             /* Make sure the soft mute status stays in sync */
@@ -1455,22 +1498,23 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
         }
     }
 
+
     return s->muted;
 }
 
 /* Called from main thread */
-void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) {
+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 */
 
-    if (s->muted == new_muted) {
-        s->save_muted = s->save_muted || save;
+    if (s->muted == new_muted)
         return;
-    }
 
     s->muted = new_muted;
-    s->save_muted = save;
+    s->save_muted = TRUE;
 
     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
 }
@@ -1478,6 +1522,7 @@ void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) {
 /* 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);
@@ -1491,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)
@@ -1527,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);
@@ -1545,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);
@@ -1563,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;
@@ -1596,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;
 
@@ -1933,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)
@@ -1948,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);
@@ -1956,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);
@@ -1967,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);
 
@@ -1983,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);
 
@@ -1996,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)
@@ -2025,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);
@@ -2061,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)
@@ -2076,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);
@@ -2094,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);
@@ -2106,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;
@@ -2115,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);
     }
 }
@@ -2123,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);
@@ -2136,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;
@@ -2147,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);
     }
@@ -2156,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
@@ -2190,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);
 
@@ -2211,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);
@@ -2227,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);
     }
@@ -2240,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)
@@ -2257,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;
@@ -2270,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;
@@ -2283,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);
@@ -2314,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;
 
@@ -2383,30 +2451,35 @@ pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
 }
 
 pa_bool_t pa_device_init_description(pa_proplist *p) {
-    const char *s;
+    const char *s, *d = NULL, *k;
     pa_assert(p);
 
     if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
         return TRUE;
 
     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
-        if (pa_streq(s, "internal")) {
-            pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
-            return TRUE;
-        }
+        if (pa_streq(s, "internal"))
+            d = _("Internal Audio");
 
-    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
-        if (pa_streq(s, "modem")) {
-            pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
-            return TRUE;
-        }
+    if (!d)
+        if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
+            if (pa_streq(s, "modem"))
+                d = _("Modem");
 
-    if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
-        pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
-        return TRUE;
-    }
+    if (!d)
+        d = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME);
 
-    return FALSE;
+    if (!d)
+        return FALSE;
+
+    k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
+
+    if (d && k)
+        pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
+    else if (d)
+        pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
+
+    return TRUE;
 }
 
 pa_bool_t pa_device_init_intended_roles(pa_proplist *p) {