add functions that modules can call whenever they now the volume changed
[platform/upstream/pulseaudio.git] / src / pulsecore / sink.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 #include <pulse/introspect.h>
32 #include <pulse/utf8.h>
33 #include <pulse/xmalloc.h>
34 #include <pulse/timeval.h>
35 #include <pulse/util.h>
36 #include <pulse/i18n.h>
37
38 #include <pulsecore/sink-input.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/core-util.h>
41 #include <pulsecore/sample-util.h>
42 #include <pulsecore/core-subscribe.h>
43 #include <pulsecore/log.h>
44 #include <pulsecore/macro.h>
45 #include <pulsecore/play-memblockq.h>
46
47 #include "sink.h"
48
49 #define MAX_MIX_CHANNELS 32
50 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
51 #define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
52
53 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
54
55 static void sink_free(pa_object *s);
56
57 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
58     pa_assert(data);
59
60     memset(data, 0, sizeof(*data));
61     data->proplist = pa_proplist_new();
62
63     return data;
64 }
65
66 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
67     pa_assert(data);
68
69     pa_xfree(data->name);
70     data->name = pa_xstrdup(name);
71 }
72
73 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
74     pa_assert(data);
75
76     if ((data->sample_spec_is_set = !!spec))
77         data->sample_spec = *spec;
78 }
79
80 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
81     pa_assert(data);
82
83     if ((data->channel_map_is_set = !!map))
84         data->channel_map = *map;
85 }
86
87 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
88     pa_assert(data);
89
90     if ((data->volume_is_set = !!volume))
91         data->volume = *volume;
92 }
93
94 void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
95     pa_assert(data);
96
97     data->muted_is_set = TRUE;
98     data->muted = !!mute;
99 }
100
101 void pa_sink_new_data_done(pa_sink_new_data *data) {
102     pa_assert(data);
103
104     pa_xfree(data->name);
105     pa_proplist_free(data->proplist);
106 }
107
108 /* Called from main context */
109 static void reset_callbacks(pa_sink *s) {
110     pa_assert(s);
111
112     s->set_state = NULL;
113     s->get_volume = NULL;
114     s->set_volume = NULL;
115     s->get_mute = NULL;
116     s->set_mute = NULL;
117     s->request_rewind = NULL;
118     s->update_requested_latency = NULL;
119 }
120
121 /* Called from main context */
122 pa_sink* pa_sink_new(
123         pa_core *core,
124         pa_sink_new_data *data,
125         pa_sink_flags_t flags) {
126
127     pa_sink *s;
128     const char *name;
129     char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
130     pa_source_new_data source_data;
131     const char *dn;
132     char *pt;
133
134     pa_assert(core);
135     pa_assert(data);
136     pa_assert(data->name);
137
138     s = pa_msgobject_new(pa_sink);
139
140     if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
141         pa_xfree(s);
142         return NULL;
143     }
144
145     pa_sink_new_data_set_name(data, name);
146
147     if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
148         pa_xfree(s);
149         pa_namereg_unregister(core, name);
150         return NULL;
151     }
152
153     pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
154     pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
155
156     pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
157
158     if (!data->channel_map_is_set)
159         pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
160
161     pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
162     pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
163
164     if (!data->volume_is_set)
165         pa_cvolume_reset(&data->volume, data->sample_spec.channels);
166
167     pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
168     pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
169
170     if (!data->muted_is_set)
171         data->muted = FALSE;
172
173     if (data->card)
174         pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
175
176     pa_device_init_description(data->proplist);
177     pa_device_init_icon(data->proplist, TRUE);
178
179     if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
180         pa_xfree(s);
181         pa_namereg_unregister(core, name);
182         return NULL;
183     }
184
185     s->parent.parent.free = sink_free;
186     s->parent.process_msg = pa_sink_process_msg;
187
188     s->core = core;
189     s->state = PA_SINK_INIT;
190     s->flags = flags;
191     s->name = pa_xstrdup(name);
192     s->proplist = pa_proplist_copy(data->proplist);
193     s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
194     s->module = data->module;
195     s->card = data->card;
196
197     s->sample_spec = data->sample_spec;
198     s->channel_map = data->channel_map;
199
200     s->inputs = pa_idxset_new(NULL, NULL);
201     s->n_corked = 0;
202
203     s->virtual_volume = data->volume;
204     pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
205     s->base_volume = PA_VOLUME_NORM;
206     s->n_volume_steps = PA_VOLUME_NORM+1;
207     s->muted = data->muted;
208     s->refresh_volume = s->refresh_muted = FALSE;
209
210     reset_callbacks(s);
211     s->userdata = NULL;
212
213     s->asyncmsgq = NULL;
214     s->rtpoll = NULL;
215
216     pa_silence_memchunk_get(
217             &core->silence_cache,
218             core->mempool,
219             &s->silence,
220             &s->sample_spec,
221             0);
222
223     s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
224     s->thread_info.soft_volume =  s->soft_volume;
225     s->thread_info.soft_muted = s->muted;
226     s->thread_info.state = s->state;
227     s->thread_info.rewind_nbytes = 0;
228     s->thread_info.rewind_requested = FALSE;
229     s->thread_info.max_rewind = 0;
230     s->thread_info.max_request = 0;
231     s->thread_info.requested_latency_valid = FALSE;
232     s->thread_info.requested_latency = 0;
233     s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
234     s->thread_info.max_latency = 0;
235
236     pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
237
238     if (s->card)
239         pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
240
241     pt = pa_proplist_to_string_sep(s->proplist, "\n    ");
242     pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n    %s",
243                 s->index,
244                 s->name,
245                 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
246                 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
247                 pt);
248     pa_xfree(pt);
249
250     pa_source_new_data_init(&source_data);
251     pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
252     pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
253     source_data.name = pa_sprintf_malloc("%s.monitor", name);
254     source_data.driver = data->driver;
255     source_data.module = data->module;
256     source_data.card = data->card;
257
258     dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
259     pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
260     pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
261
262     s->monitor_source = pa_source_new(core, &source_data, PA_SOURCE_LATENCY);
263
264     pa_source_new_data_done(&source_data);
265
266     if (!s->monitor_source) {
267         pa_sink_unlink(s);
268         pa_sink_unref(s);
269         return NULL;
270     }
271
272     s->monitor_source->monitor_of = s;
273
274     pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
275     pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
276
277     return s;
278 }
279
280 /* Called from main context */
281 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
282     int ret;
283     pa_bool_t suspend_change;
284     pa_sink_state_t original_state;
285
286     pa_assert(s);
287
288     if (s->state == state)
289         return 0;
290
291     original_state = s->state;
292
293     suspend_change =
294         (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
295         (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
296
297     if (s->set_state)
298         if ((ret = s->set_state(s, state)) < 0)
299             return ret;
300
301     if (s->asyncmsgq)
302         if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
303
304             if (s->set_state)
305                 s->set_state(s, original_state);
306
307             return ret;
308         }
309
310     s->state = state;
311
312     if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
313         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
314         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
315     }
316
317     if (suspend_change) {
318         pa_sink_input *i;
319         uint32_t idx;
320
321         /* We're suspending or resuming, tell everyone about it */
322
323         for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
324             if (s->state == PA_SINK_SUSPENDED &&
325                 (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
326                 pa_sink_input_kill(i);
327             else if (i->suspend)
328                 i->suspend(i, state == PA_SINK_SUSPENDED);
329
330         if (s->monitor_source)
331             pa_source_sync_suspend(s->monitor_source);
332     }
333
334     return 0;
335 }
336
337 /* Called from main context */
338 void pa_sink_put(pa_sink* s) {
339     pa_sink_assert_ref(s);
340
341     pa_assert(s->state == PA_SINK_INIT);
342
343     /* The following fields must be initialized properly when calling _put() */
344     pa_assert(s->asyncmsgq);
345     pa_assert(s->rtpoll);
346     pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
347               s->thread_info.min_latency <= s->thread_info.max_latency);
348
349     if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
350         s->flags |= PA_SINK_DECIBEL_VOLUME;
351
352         s->thread_info.soft_volume = s->soft_volume;
353         s->thread_info.soft_muted = s->muted;
354     }
355
356     if (s->flags & PA_SINK_DECIBEL_VOLUME)
357         s->n_volume_steps = PA_VOLUME_NORM+1;
358
359     if (s->core->flat_volumes)
360         if (s->flags & PA_SINK_DECIBEL_VOLUME)
361             s->flags |= PA_SINK_FLAT_VOLUME;
362
363     pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
364
365     pa_source_put(s->monitor_source);
366
367     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
368     pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
369 }
370
371 /* Called from main context */
372 void pa_sink_unlink(pa_sink* s) {
373     pa_bool_t linked;
374     pa_sink_input *i, *j = NULL;
375
376     pa_assert(s);
377
378     /* Please note that pa_sink_unlink() does more than simply
379      * reversing pa_sink_put(). It also undoes the registrations
380      * already done in pa_sink_new()! */
381
382     /* All operations here shall be idempotent, i.e. pa_sink_unlink()
383      * may be called multiple times on the same sink without bad
384      * effects. */
385
386     linked = PA_SINK_IS_LINKED(s->state);
387
388     if (linked)
389         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
390
391     if (s->state != PA_SINK_UNLINKED)
392         pa_namereg_unregister(s->core, s->name);
393     pa_idxset_remove_by_data(s->core->sinks, s, NULL);
394
395     if (s->card)
396         pa_idxset_remove_by_data(s->card->sinks, s, NULL);
397
398     while ((i = pa_idxset_first(s->inputs, NULL))) {
399         pa_assert(i != j);
400         pa_sink_input_kill(i);
401         j = i;
402     }
403
404     if (linked)
405         sink_set_state(s, PA_SINK_UNLINKED);
406     else
407         s->state = PA_SINK_UNLINKED;
408
409     reset_callbacks(s);
410
411     if (s->monitor_source)
412         pa_source_unlink(s->monitor_source);
413
414     if (linked) {
415         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
416         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
417     }
418 }
419
420 /* Called from main context */
421 static void sink_free(pa_object *o) {
422     pa_sink *s = PA_SINK(o);
423     pa_sink_input *i;
424
425     pa_assert(s);
426     pa_assert(pa_sink_refcnt(s) == 0);
427
428     if (PA_SINK_IS_LINKED(s->state))
429         pa_sink_unlink(s);
430
431     pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
432
433     if (s->monitor_source) {
434         pa_source_unref(s->monitor_source);
435         s->monitor_source = NULL;
436     }
437
438     pa_idxset_free(s->inputs, NULL, NULL);
439
440     while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
441         pa_sink_input_unref(i);
442
443     pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
444
445     if (s->silence.memblock)
446         pa_memblock_unref(s->silence.memblock);
447
448     pa_xfree(s->name);
449     pa_xfree(s->driver);
450
451     if (s->proplist)
452         pa_proplist_free(s->proplist);
453
454     pa_xfree(s);
455 }
456
457 /* Called from main context */
458 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
459     pa_sink_assert_ref(s);
460
461     s->asyncmsgq = q;
462
463     if (s->monitor_source)
464         pa_source_set_asyncmsgq(s->monitor_source, q);
465 }
466
467 /* Called from main context */
468 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
469     pa_sink_assert_ref(s);
470
471     s->rtpoll = p;
472     if (s->monitor_source)
473         pa_source_set_rtpoll(s->monitor_source, p);
474 }
475
476 /* Called from main context */
477 int pa_sink_update_status(pa_sink*s) {
478     pa_sink_assert_ref(s);
479     pa_assert(PA_SINK_IS_LINKED(s->state));
480
481     if (s->state == PA_SINK_SUSPENDED)
482         return 0;
483
484     return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
485 }
486
487 /* Called from main context */
488 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
489     pa_sink_assert_ref(s);
490     pa_assert(PA_SINK_IS_LINKED(s->state));
491
492     if (suspend)
493         return sink_set_state(s, PA_SINK_SUSPENDED);
494     else
495         return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
496 }
497
498 /* Called from main context */
499 pa_queue *pa_sink_move_all_start(pa_sink *s) {
500     pa_queue *q;
501     pa_sink_input *i, *n;
502     uint32_t idx;
503
504     pa_sink_assert_ref(s);
505     pa_assert(PA_SINK_IS_LINKED(s->state));
506
507     q = pa_queue_new();
508
509     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
510         n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
511
512         if (pa_sink_input_start_move(i) >= 0)
513             pa_queue_push(q, pa_sink_input_ref(i));
514     }
515
516     return q;
517 }
518
519 /* Called from main context */
520 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
521     pa_sink_input *i;
522
523     pa_sink_assert_ref(s);
524     pa_assert(PA_SINK_IS_LINKED(s->state));
525     pa_assert(q);
526
527     while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
528         if (pa_sink_input_finish_move(i, s, save) < 0)
529             pa_sink_input_kill(i);
530
531         pa_sink_input_unref(i);
532     }
533
534     pa_queue_free(q, NULL, NULL);
535 }
536
537 /* Called from main context */
538 void pa_sink_move_all_fail(pa_queue *q) {
539     pa_sink_input *i;
540     pa_assert(q);
541
542     while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
543         if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
544             pa_sink_input_kill(i);
545             pa_sink_input_unref(i);
546         }
547     }
548
549     pa_queue_free(q, NULL, NULL);
550 }
551
552 /* Called from IO thread context */
553 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
554     pa_sink_input *i;
555     void *state = NULL;
556     pa_sink_assert_ref(s);
557     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
558
559     /* If nobody requested this and this is actually no real rewind
560      * then we can short cut this */
561     if (!s->thread_info.rewind_requested && nbytes <= 0)
562         return;
563
564     s->thread_info.rewind_nbytes = 0;
565     s->thread_info.rewind_requested = FALSE;
566
567     if (s->thread_info.state == PA_SINK_SUSPENDED)
568         return;
569
570     if (nbytes > 0)
571         pa_log_debug("Processing rewind...");
572
573     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
574         pa_sink_input_assert_ref(i);
575         pa_sink_input_process_rewind(i, nbytes);
576     }
577
578     if (nbytes > 0)
579         if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
580             pa_source_process_rewind(s->monitor_source, nbytes);
581 }
582
583 /* Called from IO thread context */
584 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
585     pa_sink_input *i;
586     unsigned n = 0;
587     void *state = NULL;
588     size_t mixlength = *length;
589
590     pa_sink_assert_ref(s);
591     pa_assert(info);
592
593     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
594         pa_sink_input_assert_ref(i);
595
596         pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
597
598         if (mixlength == 0 || info->chunk.length < mixlength)
599             mixlength = info->chunk.length;
600
601         if (pa_memblock_is_silence(info->chunk.memblock)) {
602             pa_memblock_unref(info->chunk.memblock);
603             continue;
604         }
605
606         info->userdata = pa_sink_input_ref(i);
607
608         pa_assert(info->chunk.memblock);
609         pa_assert(info->chunk.length > 0);
610
611         info++;
612         n++;
613         maxinfo--;
614     }
615
616     if (mixlength > 0)
617         *length = mixlength;
618
619     return n;
620 }
621
622 /* Called from IO thread context */
623 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
624     pa_sink_input *i;
625     void *state = NULL;
626     unsigned p = 0;
627     unsigned n_unreffed = 0;
628
629     pa_sink_assert_ref(s);
630     pa_assert(result);
631     pa_assert(result->memblock);
632     pa_assert(result->length > 0);
633
634     /* We optimize for the case where the order of the inputs has not changed */
635
636     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
637         unsigned j;
638         pa_mix_info* m = NULL;
639
640         pa_sink_input_assert_ref(i);
641
642         /* Let's try to find the matching entry info the pa_mix_info array */
643         for (j = 0; j < n; j ++) {
644
645             if (info[p].userdata == i) {
646                 m = info + p;
647                 break;
648             }
649
650             p++;
651             if (p >= n)
652                 p = 0;
653         }
654
655         /* Drop read data */
656         pa_sink_input_drop(i, result->length);
657
658         if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
659
660             if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
661                 void *ostate = NULL;
662                 pa_source_output *o;
663                 pa_memchunk c;
664
665                 if (m && m->chunk.memblock) {
666                     c = m->chunk;
667                     pa_memblock_ref(c.memblock);
668                     pa_assert(result->length <= c.length);
669                     c.length = result->length;
670
671                     pa_memchunk_make_writable(&c, 0);
672                     pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
673                 } else {
674                     c = s->silence;
675                     pa_memblock_ref(c.memblock);
676                     pa_assert(result->length <= c.length);
677                     c.length = result->length;
678                 }
679
680                 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
681                     pa_source_output_assert_ref(o);
682                     pa_assert(o->direct_on_input == i);
683                     pa_source_post_direct(s->monitor_source, o, &c);
684                 }
685
686                 pa_memblock_unref(c.memblock);
687             }
688         }
689
690         if (m) {
691             if (m->chunk.memblock)
692                 pa_memblock_unref(m->chunk.memblock);
693                 pa_memchunk_reset(&m->chunk);
694
695             pa_sink_input_unref(m->userdata);
696             m->userdata = NULL;
697
698             n_unreffed += 1;
699         }
700     }
701
702     /* Now drop references to entries that are included in the
703      * pa_mix_info array but don't exist anymore */
704
705     if (n_unreffed < n) {
706         for (; n > 0; info++, n--) {
707             if (info->userdata)
708                 pa_sink_input_unref(info->userdata);
709             if (info->chunk.memblock)
710                 pa_memblock_unref(info->chunk.memblock);
711         }
712     }
713
714     if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
715         pa_source_post(s->monitor_source, result);
716 }
717
718 /* Called from IO thread context */
719 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
720     pa_mix_info info[MAX_MIX_CHANNELS];
721     unsigned n;
722     size_t block_size_max;
723
724     pa_sink_assert_ref(s);
725     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
726     pa_assert(pa_frame_aligned(length, &s->sample_spec));
727     pa_assert(result);
728
729     pa_sink_ref(s);
730
731     pa_assert(!s->thread_info.rewind_requested);
732     pa_assert(s->thread_info.rewind_nbytes == 0);
733
734     if (s->thread_info.state == PA_SINK_SUSPENDED) {
735         result->memblock = pa_memblock_ref(s->silence.memblock);
736         result->index = s->silence.index;
737         result->length = PA_MIN(s->silence.length, length);
738         return;
739     }
740
741     if (length <= 0)
742         length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
743
744     block_size_max = pa_mempool_block_size_max(s->core->mempool);
745     if (length > block_size_max)
746         length = pa_frame_align(block_size_max, &s->sample_spec);
747
748     pa_assert(length > 0);
749
750     n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
751
752     if (n == 0) {
753
754         *result = s->silence;
755         pa_memblock_ref(result->memblock);
756
757         if (result->length > length)
758             result->length = length;
759
760     } else if (n == 1) {
761         pa_cvolume volume;
762
763         *result = info[0].chunk;
764         pa_memblock_ref(result->memblock);
765
766         if (result->length > length)
767             result->length = length;
768
769         pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
770
771         if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
772             pa_memchunk_make_writable(result, 0);
773             if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
774                 pa_silence_memchunk(result, &s->sample_spec);
775             else
776                 pa_volume_memchunk(result, &s->sample_spec, &volume);
777         }
778     } else {
779         void *ptr;
780         result->memblock = pa_memblock_new(s->core->mempool, length);
781
782         ptr = pa_memblock_acquire(result->memblock);
783         result->length = pa_mix(info, n,
784                                 ptr, length,
785                                 &s->sample_spec,
786                                 &s->thread_info.soft_volume,
787                                 s->thread_info.soft_muted);
788         pa_memblock_release(result->memblock);
789
790         result->index = 0;
791     }
792
793     inputs_drop(s, info, n, result);
794
795     pa_sink_unref(s);
796 }
797
798 /* Called from IO thread context */
799 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
800     pa_mix_info info[MAX_MIX_CHANNELS];
801     unsigned n;
802     size_t length, block_size_max;
803
804     pa_sink_assert_ref(s);
805     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
806     pa_assert(target);
807     pa_assert(target->memblock);
808     pa_assert(target->length > 0);
809     pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
810
811     pa_sink_ref(s);
812
813     pa_assert(!s->thread_info.rewind_requested);
814     pa_assert(s->thread_info.rewind_nbytes == 0);
815
816     if (s->thread_info.state == PA_SINK_SUSPENDED) {
817         pa_silence_memchunk(target, &s->sample_spec);
818         return;
819     }
820
821     length = target->length;
822     block_size_max = pa_mempool_block_size_max(s->core->mempool);
823     if (length > block_size_max)
824         length = pa_frame_align(block_size_max, &s->sample_spec);
825
826     pa_assert(length > 0);
827
828     n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
829
830     if (n == 0) {
831         if (target->length > length)
832             target->length = length;
833
834         pa_silence_memchunk(target, &s->sample_spec);
835     } else if (n == 1) {
836         pa_cvolume volume;
837
838         if (target->length > length)
839             target->length = length;
840
841         pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
842
843         if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
844             pa_silence_memchunk(target, &s->sample_spec);
845         else {
846             pa_memchunk vchunk;
847
848             vchunk = info[0].chunk;
849             pa_memblock_ref(vchunk.memblock);
850
851             if (vchunk.length > length)
852                 vchunk.length = length;
853
854             if (!pa_cvolume_is_norm(&volume)) {
855                 pa_memchunk_make_writable(&vchunk, 0);
856                 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
857             }
858
859             pa_memchunk_memcpy(target, &vchunk);
860             pa_memblock_unref(vchunk.memblock);
861         }
862
863     } else {
864         void *ptr;
865
866         ptr = pa_memblock_acquire(target->memblock);
867
868         target->length = pa_mix(info, n,
869                                 (uint8_t*) ptr + target->index, length,
870                                 &s->sample_spec,
871                                 &s->thread_info.soft_volume,
872                                 s->thread_info.soft_muted);
873
874         pa_memblock_release(target->memblock);
875     }
876
877     inputs_drop(s, info, n, target);
878
879     pa_sink_unref(s);
880 }
881
882 /* Called from IO thread context */
883 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
884     pa_memchunk chunk;
885     size_t l, d;
886
887     pa_sink_assert_ref(s);
888     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
889     pa_assert(target);
890     pa_assert(target->memblock);
891     pa_assert(target->length > 0);
892     pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
893
894     pa_sink_ref(s);
895
896     pa_assert(!s->thread_info.rewind_requested);
897     pa_assert(s->thread_info.rewind_nbytes == 0);
898
899     l = target->length;
900     d = 0;
901     while (l > 0) {
902         chunk = *target;
903         chunk.index += d;
904         chunk.length -= d;
905
906         pa_sink_render_into(s, &chunk);
907
908         d += chunk.length;
909         l -= chunk.length;
910     }
911
912     pa_sink_unref(s);
913 }
914
915 /* Called from IO thread context */
916 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
917     pa_sink_assert_ref(s);
918     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
919     pa_assert(length > 0);
920     pa_assert(pa_frame_aligned(length, &s->sample_spec));
921     pa_assert(result);
922
923     pa_assert(!s->thread_info.rewind_requested);
924     pa_assert(s->thread_info.rewind_nbytes == 0);
925
926     /*** This needs optimization ***/
927
928     result->index = 0;
929     result->length = length;
930     result->memblock = pa_memblock_new(s->core->mempool, length);
931
932     pa_sink_render_into_full(s, result);
933 }
934
935 /* Called from main thread */
936 pa_usec_t pa_sink_get_latency(pa_sink *s) {
937     pa_usec_t usec = 0;
938
939     pa_sink_assert_ref(s);
940     pa_assert(PA_SINK_IS_LINKED(s->state));
941
942     /* The returned value is supposed to be in the time domain of the sound card! */
943
944     if (s->state == PA_SINK_SUSPENDED)
945         return 0;
946
947     if (!(s->flags & PA_SINK_LATENCY))
948         return 0;
949
950     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
951
952     return usec;
953 }
954
955 /* Called from main thread */
956 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
957     pa_sink_input *i;
958     uint32_t idx;
959
960     pa_sink_assert_ref(s);
961     pa_assert(new_volume);
962     pa_assert(PA_SINK_IS_LINKED(s->state));
963     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
964
965     /* This is called whenever a sink input volume changes and we
966      * might need to fix up the sink volume accordingly. Please note
967      * that we don't actually update the sinks volume here, we only
968      * return how it needs to be updated. The caller should then call
969      * pa_sink_set_flat_volume().*/
970
971     if (pa_idxset_isempty(s->inputs)) {
972         /* In the special case that we have no sink input we leave the
973          * volume unmodified. */
974         *new_volume = s->virtual_volume;
975         return;
976     }
977
978     pa_cvolume_mute(new_volume, s->channel_map.channels);
979
980     /* First let's determine the new maximum volume of all inputs
981      * connected to this sink */
982     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
983         unsigned c;
984         pa_cvolume remapped_volume;
985
986         remapped_volume = i->virtual_volume;
987         pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
988
989         for (c = 0; c < new_volume->channels; c++)
990             if (remapped_volume.values[c] > new_volume->values[c])
991                 new_volume->values[c] = remapped_volume.values[c];
992     }
993
994     /* Then, let's update the soft volumes of all inputs connected
995      * to this sink */
996     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
997         pa_cvolume remapped_new_volume;
998
999         remapped_new_volume = *new_volume;
1000         pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1001         pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
1002         pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor);
1003
1004         /* Hooks have the ability to play games with i->soft_volume */
1005         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1006
1007         /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
1008          * we want the update to have atomically with the sink
1009          * volume update, hence we do it within the
1010          * pa_sink_set_flat_volume() call below*/
1011     }
1012 }
1013
1014 /* Called from main thread */
1015 void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
1016     pa_sink_input *i;
1017     uint32_t idx;
1018
1019     pa_sink_assert_ref(s);
1020     pa_assert(old_volume);
1021     pa_assert(PA_SINK_IS_LINKED(s->state));
1022     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1023
1024     /* This is called whenever the sink volume changes that is not
1025      * caused by a sink input volume change. We need to fix up the
1026      * sink input volumes accordingly */
1027
1028     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1029         pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
1030         unsigned c;
1031
1032         remapped_new_volume = s->virtual_volume;
1033         pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1034
1035         remapped_old_volume = *old_volume;
1036         pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
1037
1038         for (c = 0; c < i->sample_spec.channels; c++)
1039
1040             if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
1041                 fixed_volume.values[c] = PA_VOLUME_MUTED;
1042             else
1043                 fixed_volume.values[c] = (pa_volume_t)
1044                     ((uint64_t) i->virtual_volume.values[c] *
1045                      (uint64_t) remapped_new_volume.values[c] /
1046                      (uint64_t) remapped_old_volume.values[c]);
1047
1048         fixed_volume.channels = i->virtual_volume.channels;
1049
1050         if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
1051             i->virtual_volume = fixed_volume;
1052
1053             /* The virtual volume changed, let's tell people so */
1054             pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1055         }
1056     }
1057 }
1058
1059 /* Called from main thread */
1060 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1061     pa_cvolume old_virtual_volume;
1062     pa_bool_t virtual_volume_changed;
1063
1064     pa_sink_assert_ref(s);
1065     pa_assert(PA_SINK_IS_LINKED(s->state));
1066     pa_assert(volume);
1067     pa_assert(pa_cvolume_valid(volume));
1068     pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1069
1070     old_virtual_volume = s->virtual_volume;
1071     s->virtual_volume = *volume;
1072     virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
1073
1074     /* Propagate this volume change back to the inputs */
1075     if (virtual_volume_changed)
1076         if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1077             pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1078
1079     if (s->set_volume) {
1080         /* If we have a function set_volume(), then we do not apply a
1081          * soft volume by default. However, set_volume() is apply one
1082          * to s->soft_volume */
1083
1084         pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1085         s->set_volume(s);
1086
1087     } else
1088         /* If we have no function set_volume(), then the soft volume
1089          * becomes the virtual volume */
1090         s->soft_volume = s->virtual_volume;
1091
1092     /* This tells the sink that soft and/or virtual volume changed */
1093     if (sendmsg)
1094         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1095
1096     if (virtual_volume_changed)
1097         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1098 }
1099
1100 /* Called from main thread. Only to be called by sink implementor */
1101 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1102     pa_sink_assert_ref(s);
1103     pa_assert(volume);
1104
1105     s->soft_volume = *volume;
1106
1107     if (PA_SINK_IS_LINKED(s->state))
1108         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1109     else
1110         s->thread_info.soft_volume = *volume;
1111 }
1112
1113 /* Called from main thread */
1114 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1115     pa_sink_assert_ref(s);
1116
1117     if (s->refresh_volume || force_refresh) {
1118         struct pa_cvolume old_virtual_volume = s->virtual_volume;
1119
1120         if (s->get_volume)
1121             s->get_volume(s);
1122
1123         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1124
1125         if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1126
1127             if (s->flags & PA_SINK_FLAT_VOLUME)
1128                 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1129
1130             pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1131         }
1132     }
1133
1134     return &s->virtual_volume;
1135 }
1136
1137 /* Called from main thread */
1138 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
1139     pa_sink_assert_ref(s);
1140
1141     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1142
1143     if (pa_cvolume_equal(&s->virtual_volume, new_volume))
1144         return;
1145
1146     s->virtual_volume = *new_volume;
1147     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1148 }
1149
1150 /* Called from main thread */
1151 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1152     pa_bool_t old_muted;
1153
1154     pa_sink_assert_ref(s);
1155     pa_assert(PA_SINK_IS_LINKED(s->state));
1156
1157     old_muted = s->muted;
1158     s->muted = mute;
1159
1160     if (s->set_mute)
1161         s->set_mute(s);
1162
1163     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1164
1165     if (old_muted != s->muted)
1166         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1167 }
1168
1169 /* Called from main thread */
1170 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1171
1172     pa_sink_assert_ref(s);
1173
1174     if (s->refresh_muted || force_refresh) {
1175         pa_bool_t old_muted = s->muted;
1176
1177         if (s->get_mute)
1178             s->get_mute(s);
1179
1180         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1181
1182         if (old_muted != s->muted)
1183             pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1184     }
1185
1186     return s->muted;
1187 }
1188
1189 /* Called from main thread */
1190 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
1191     pa_sink_assert_ref(s);
1192
1193     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1194
1195     if (s->muted == new_muted)
1196         return;
1197
1198     s->muted = new_muted;
1199     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1200 }
1201
1202 /* Called from main thread */
1203 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1204
1205     pa_sink_assert_ref(s);
1206     pa_assert(p);
1207
1208     pa_proplist_update(s->proplist, mode, p);
1209
1210     if (PA_SINK_IS_LINKED(s->state)) {
1211         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1212         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1213     }
1214
1215     return TRUE;
1216 }
1217
1218 /* Called from main thread */
1219 void pa_sink_set_description(pa_sink *s, const char *description) {
1220     const char *old;
1221     pa_sink_assert_ref(s);
1222
1223     if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1224         return;
1225
1226     old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1227
1228     if (old && description && !strcmp(old, description))
1229         return;
1230
1231     if (description)
1232         pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1233     else
1234         pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1235
1236     if (s->monitor_source) {
1237         char *n;
1238
1239         n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1240         pa_source_set_description(s->monitor_source, n);
1241         pa_xfree(n);
1242     }
1243
1244     if (PA_SINK_IS_LINKED(s->state)) {
1245         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1246         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1247     }
1248 }
1249
1250 /* Called from main thread */
1251 unsigned pa_sink_linked_by(pa_sink *s) {
1252     unsigned ret;
1253
1254     pa_sink_assert_ref(s);
1255     pa_assert(PA_SINK_IS_LINKED(s->state));
1256
1257     ret = pa_idxset_size(s->inputs);
1258
1259     /* We add in the number of streams connected to us here. Please
1260      * note the asymmmetry to pa_sink_used_by()! */
1261
1262     if (s->monitor_source)
1263         ret += pa_source_linked_by(s->monitor_source);
1264
1265     return ret;
1266 }
1267
1268 /* Called from main thread */
1269 unsigned pa_sink_used_by(pa_sink *s) {
1270     unsigned ret;
1271
1272     pa_sink_assert_ref(s);
1273     pa_assert(PA_SINK_IS_LINKED(s->state));
1274
1275     ret = pa_idxset_size(s->inputs);
1276     pa_assert(ret >= s->n_corked);
1277
1278     /* Streams connected to our monitor source do not matter for
1279      * pa_sink_used_by()!.*/
1280
1281     return ret - s->n_corked;
1282 }
1283
1284 /* Called from main thread */
1285 unsigned pa_sink_check_suspend(pa_sink *s) {
1286     unsigned ret;
1287     pa_sink_input *i;
1288     uint32_t idx;
1289
1290     pa_sink_assert_ref(s);
1291
1292     if (!PA_SINK_IS_LINKED(s->state))
1293         return 0;
1294
1295     ret = 0;
1296
1297     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1298         pa_sink_input_state_t st;
1299
1300         st = pa_sink_input_get_state(i);
1301         pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1302
1303         if (st == PA_SINK_INPUT_CORKED)
1304             continue;
1305
1306         if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1307             continue;
1308
1309         ret ++;
1310     }
1311
1312     if (s->monitor_source)
1313         ret += pa_source_check_suspend(s->monitor_source);
1314
1315     return ret;
1316 }
1317
1318 /* Called from the IO thread */
1319 static void sync_input_volumes_within_thread(pa_sink *s) {
1320     pa_sink_input *i;
1321     void *state = NULL;
1322
1323     pa_sink_assert_ref(s);
1324
1325     while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1326         if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1327             continue;
1328
1329         i->thread_info.soft_volume = i->soft_volume;
1330         pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1331     }
1332 }
1333
1334 /* Called from IO thread, except when it is not */
1335 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1336     pa_sink *s = PA_SINK(o);
1337     pa_sink_assert_ref(s);
1338
1339     switch ((pa_sink_message_t) code) {
1340
1341         case PA_SINK_MESSAGE_ADD_INPUT: {
1342             pa_sink_input *i = PA_SINK_INPUT(userdata);
1343
1344             /* If you change anything here, make sure to change the
1345              * sink input handling a few lines down at
1346              * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1347
1348             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1349
1350             /* Since the caller sleeps in pa_sink_input_put(), we can
1351              * safely access data outside of thread_info even though
1352              * it is mutable */
1353
1354             if ((i->thread_info.sync_prev = i->sync_prev)) {
1355                 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1356                 pa_assert(i->sync_prev->sync_next == i);
1357                 i->thread_info.sync_prev->thread_info.sync_next = i;
1358             }
1359
1360             if ((i->thread_info.sync_next = i->sync_next)) {
1361                 pa_assert(i->sink == i->thread_info.sync_next->sink);
1362                 pa_assert(i->sync_next->sync_prev == i);
1363                 i->thread_info.sync_next->thread_info.sync_prev = i;
1364             }
1365
1366             pa_assert(!i->thread_info.attached);
1367             i->thread_info.attached = TRUE;
1368
1369             if (i->attach)
1370                 i->attach(i);
1371
1372             pa_sink_input_set_state_within_thread(i, i->state);
1373
1374             /* The requested latency of the sink input needs to be
1375              * fixed up and then configured on the sink */
1376
1377             if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1378                 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1379
1380             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1381             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1382
1383             /* We don't rewind here automatically. This is left to the
1384              * sink input implementor because some sink inputs need a
1385              * slow start, i.e. need some time to buffer client
1386              * samples before beginning streaming. */
1387
1388             /* In flat volume mode we need to update the volume as
1389              * well */
1390             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1391         }
1392
1393         case PA_SINK_MESSAGE_REMOVE_INPUT: {
1394             pa_sink_input *i = PA_SINK_INPUT(userdata);
1395
1396             /* If you change anything here, make sure to change the
1397              * sink input handling a few lines down at
1398              * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1399
1400             if (i->detach)
1401                 i->detach(i);
1402
1403             pa_sink_input_set_state_within_thread(i, i->state);
1404
1405             pa_assert(i->thread_info.attached);
1406             i->thread_info.attached = FALSE;
1407
1408             /* Since the caller sleeps in pa_sink_input_unlink(),
1409              * we can safely access data outside of thread_info even
1410              * though it is mutable */
1411
1412             pa_assert(!i->sync_prev);
1413             pa_assert(!i->sync_next);
1414
1415             if (i->thread_info.sync_prev) {
1416                 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1417                 i->thread_info.sync_prev = NULL;
1418             }
1419
1420             if (i->thread_info.sync_next) {
1421                 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1422                 i->thread_info.sync_next = NULL;
1423             }
1424
1425             if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1426                 pa_sink_input_unref(i);
1427
1428             pa_sink_invalidate_requested_latency(s);
1429             pa_sink_request_rewind(s, (size_t) -1);
1430
1431             /* In flat volume mode we need to update the volume as
1432              * well */
1433             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1434         }
1435
1436         case PA_SINK_MESSAGE_START_MOVE: {
1437             pa_sink_input *i = PA_SINK_INPUT(userdata);
1438
1439             /* We don't support moving synchronized streams. */
1440             pa_assert(!i->sync_prev);
1441             pa_assert(!i->sync_next);
1442             pa_assert(!i->thread_info.sync_next);
1443             pa_assert(!i->thread_info.sync_prev);
1444
1445             if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1446                 pa_usec_t usec = 0;
1447                 size_t sink_nbytes, total_nbytes;
1448
1449                 /* Get the latency of the sink */
1450                 if (!(s->flags & PA_SINK_LATENCY) ||
1451                     PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1452                     usec = 0;
1453
1454                 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1455                 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1456
1457                 if (total_nbytes > 0) {
1458                     i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1459                     i->thread_info.rewrite_flush = TRUE;
1460                     pa_sink_input_process_rewind(i, sink_nbytes);
1461                 }
1462             }
1463
1464             if (i->detach)
1465                 i->detach(i);
1466
1467             pa_assert(i->thread_info.attached);
1468             i->thread_info.attached = FALSE;
1469
1470             /* Let's remove the sink input ...*/
1471             if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1472                 pa_sink_input_unref(i);
1473
1474             pa_sink_invalidate_requested_latency(s);
1475
1476             pa_log_debug("Requesting rewind due to started move");
1477             pa_sink_request_rewind(s, (size_t) -1);
1478
1479             /* In flat volume mode we need to update the volume as
1480              * well */
1481             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1482         }
1483
1484         case PA_SINK_MESSAGE_FINISH_MOVE: {
1485             pa_sink_input *i = PA_SINK_INPUT(userdata);
1486
1487             /* We don't support moving synchronized streams. */
1488             pa_assert(!i->sync_prev);
1489             pa_assert(!i->sync_next);
1490             pa_assert(!i->thread_info.sync_next);
1491             pa_assert(!i->thread_info.sync_prev);
1492
1493             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1494
1495             pa_assert(!i->thread_info.attached);
1496             i->thread_info.attached = TRUE;
1497
1498             if (i->attach)
1499                 i->attach(i);
1500
1501             if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1502                 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1503
1504             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1505             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1506
1507             if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1508                 pa_usec_t usec = 0;
1509                 size_t nbytes;
1510
1511                 /* Get the latency of the sink */
1512                 if (!(s->flags & PA_SINK_LATENCY) ||
1513                     PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1514                     usec = 0;
1515
1516                 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1517
1518                 if (nbytes > 0)
1519                     pa_sink_input_drop(i, nbytes);
1520
1521                 pa_log_debug("Requesting rewind due to finished move");
1522                 pa_sink_request_rewind(s, nbytes);
1523             }
1524
1525             /* In flat volume mode we need to update the volume as
1526              * well */
1527             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1528         }
1529
1530         case PA_SINK_MESSAGE_SET_VOLUME:
1531
1532             if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1533                 s->thread_info.soft_volume = s->soft_volume;
1534                 pa_sink_request_rewind(s, (size_t) -1);
1535             }
1536
1537             if (s->flags & PA_SINK_FLAT_VOLUME)
1538                 sync_input_volumes_within_thread(s);
1539
1540             return 0;
1541
1542         case PA_SINK_MESSAGE_GET_VOLUME:
1543             return 0;
1544
1545         case PA_SINK_MESSAGE_SET_MUTE:
1546
1547             if (s->thread_info.soft_muted != s->muted) {
1548                 s->thread_info.soft_muted = s->muted;
1549                 pa_sink_request_rewind(s, (size_t) -1);
1550             }
1551
1552             return 0;
1553
1554         case PA_SINK_MESSAGE_GET_MUTE:
1555             return 0;
1556
1557         case PA_SINK_MESSAGE_SET_STATE:
1558
1559             s->thread_info.state = PA_PTR_TO_UINT(userdata);
1560
1561             if (s->thread_info.state == PA_SINK_SUSPENDED) {
1562                 s->thread_info.rewind_nbytes = 0;
1563                 s->thread_info.rewind_requested = FALSE;
1564             }
1565
1566             return 0;
1567
1568         case PA_SINK_MESSAGE_DETACH:
1569
1570             /* Detach all streams */
1571             pa_sink_detach_within_thread(s);
1572             return 0;
1573
1574         case PA_SINK_MESSAGE_ATTACH:
1575
1576             /* Reattach all streams */
1577             pa_sink_attach_within_thread(s);
1578             return 0;
1579
1580         case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1581
1582             pa_usec_t *usec = userdata;
1583             *usec = pa_sink_get_requested_latency_within_thread(s);
1584
1585             if (*usec == (pa_usec_t) -1)
1586                 *usec = s->thread_info.max_latency;
1587
1588             return 0;
1589         }
1590
1591         case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1592             pa_usec_t *r = userdata;
1593
1594             pa_sink_update_latency_range(s, r[0], r[1]);
1595
1596             return 0;
1597         }
1598
1599         case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1600             pa_usec_t *r = userdata;
1601
1602             r[0] = s->thread_info.min_latency;
1603             r[1] = s->thread_info.max_latency;
1604
1605             return 0;
1606         }
1607
1608         case PA_SINK_MESSAGE_GET_MAX_REWIND:
1609
1610             *((size_t*) userdata) = s->thread_info.max_rewind;
1611             return 0;
1612
1613         case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1614
1615             *((size_t*) userdata) = s->thread_info.max_request;
1616             return 0;
1617
1618         case PA_SINK_MESSAGE_GET_LATENCY:
1619         case PA_SINK_MESSAGE_MAX:
1620             ;
1621     }
1622
1623     return -1;
1624 }
1625
1626 /* Called from main thread */
1627 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1628     pa_sink *sink;
1629     uint32_t idx;
1630     int ret = 0;
1631
1632     pa_core_assert_ref(c);
1633
1634     for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1635         int r;
1636
1637         if ((r = pa_sink_suspend(sink, suspend)) < 0)
1638             ret = r;
1639     }
1640
1641     return ret;
1642 }
1643
1644 /* Called from main thread */
1645 void pa_sink_detach(pa_sink *s) {
1646     pa_sink_assert_ref(s);
1647     pa_assert(PA_SINK_IS_LINKED(s->state));
1648
1649     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1650 }
1651
1652 /* Called from main thread */
1653 void pa_sink_attach(pa_sink *s) {
1654     pa_sink_assert_ref(s);
1655     pa_assert(PA_SINK_IS_LINKED(s->state));
1656
1657     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1658 }
1659
1660 /* Called from IO thread */
1661 void pa_sink_detach_within_thread(pa_sink *s) {
1662     pa_sink_input *i;
1663     void *state = NULL;
1664
1665     pa_sink_assert_ref(s);
1666     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1667
1668     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1669         if (i->detach)
1670             i->detach(i);
1671
1672     if (s->monitor_source)
1673         pa_source_detach_within_thread(s->monitor_source);
1674 }
1675
1676 /* Called from IO thread */
1677 void pa_sink_attach_within_thread(pa_sink *s) {
1678     pa_sink_input *i;
1679     void *state = NULL;
1680
1681     pa_sink_assert_ref(s);
1682     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1683
1684     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1685         if (i->attach)
1686             i->attach(i);
1687
1688     if (s->monitor_source)
1689         pa_source_attach_within_thread(s->monitor_source);
1690 }
1691
1692 /* Called from IO thread */
1693 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1694     pa_sink_assert_ref(s);
1695     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1696
1697     if (s->thread_info.state == PA_SINK_SUSPENDED)
1698         return;
1699
1700     if (nbytes == (size_t) -1)
1701         nbytes = s->thread_info.max_rewind;
1702
1703     nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1704
1705     if (s->thread_info.rewind_requested &&
1706         nbytes <= s->thread_info.rewind_nbytes)
1707         return;
1708
1709     s->thread_info.rewind_nbytes = nbytes;
1710     s->thread_info.rewind_requested = TRUE;
1711
1712     if (s->request_rewind)
1713         s->request_rewind(s);
1714 }
1715
1716 /* Called from IO thread */
1717 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1718     pa_usec_t result = (pa_usec_t) -1;
1719     pa_sink_input *i;
1720     void *state = NULL;
1721     pa_usec_t monitor_latency;
1722
1723     pa_sink_assert_ref(s);
1724
1725     if (s->thread_info.requested_latency_valid)
1726         return s->thread_info.requested_latency;
1727
1728     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1729
1730         if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1731             (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1732             result = i->thread_info.requested_sink_latency;
1733
1734     monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1735
1736     if (monitor_latency != (pa_usec_t) -1 &&
1737         (result == (pa_usec_t) -1 || result > monitor_latency))
1738         result = monitor_latency;
1739
1740     if (result != (pa_usec_t) -1) {
1741         if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1742             result = s->thread_info.max_latency;
1743
1744         if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1745             result = s->thread_info.min_latency;
1746     }
1747
1748     s->thread_info.requested_latency = result;
1749     s->thread_info.requested_latency_valid = TRUE;
1750
1751     return result;
1752 }
1753
1754 /* Called from main thread */
1755 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1756     pa_usec_t usec = 0;
1757
1758     pa_sink_assert_ref(s);
1759     pa_assert(PA_SINK_IS_LINKED(s->state));
1760
1761     if (s->state == PA_SINK_SUSPENDED)
1762         return 0;
1763
1764     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1765     return usec;
1766 }
1767
1768 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1769 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1770     pa_sink_input *i;
1771     void *state = NULL;
1772
1773     pa_sink_assert_ref(s);
1774
1775     if (max_rewind == s->thread_info.max_rewind)
1776         return;
1777
1778     s->thread_info.max_rewind = max_rewind;
1779
1780     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1781         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1782             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1783     }
1784
1785     if (s->monitor_source)
1786         pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
1787 }
1788
1789 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1790 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1791     void *state = NULL;
1792
1793     pa_sink_assert_ref(s);
1794
1795     if (max_request == s->thread_info.max_request)
1796         return;
1797
1798     s->thread_info.max_request = max_request;
1799
1800     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1801         pa_sink_input *i;
1802
1803         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1804             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1805     }
1806 }
1807
1808 /* Called from IO thread */
1809 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1810     pa_sink_input *i;
1811     void *state = NULL;
1812
1813     pa_sink_assert_ref(s);
1814
1815     s->thread_info.requested_latency_valid = FALSE;
1816
1817     if (s->update_requested_latency)
1818         s->update_requested_latency(s);
1819
1820     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1821         if (i->update_sink_requested_latency)
1822             i->update_sink_requested_latency(i);
1823 }
1824
1825 /* Called from main thread */
1826 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1827     pa_sink_assert_ref(s);
1828
1829     /* min_latency == 0:           no limit
1830      * min_latency == (size_t) -1: default limit
1831      * min_latency anything else:  specified limit
1832      *
1833      * Similar for max_latency */
1834
1835     if (min_latency == (pa_usec_t) -1)
1836         min_latency = DEFAULT_MIN_LATENCY;
1837
1838     if (max_latency == (pa_usec_t) -1)
1839         max_latency = min_latency;
1840
1841     pa_assert(!min_latency || !max_latency ||
1842               min_latency <= max_latency);
1843
1844     if (PA_SINK_IS_LINKED(s->state)) {
1845         pa_usec_t r[2];
1846
1847         r[0] = min_latency;
1848         r[1] = max_latency;
1849
1850         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1851     } else {
1852         s->thread_info.min_latency = min_latency;
1853         s->thread_info.max_latency = max_latency;
1854
1855         s->monitor_source->thread_info.min_latency = min_latency;
1856         s->monitor_source->thread_info.max_latency = max_latency;
1857
1858         s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
1859     }
1860 }
1861
1862 /* Called from main thread */
1863 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1864    pa_sink_assert_ref(s);
1865    pa_assert(min_latency);
1866    pa_assert(max_latency);
1867
1868    if (PA_SINK_IS_LINKED(s->state)) {
1869        pa_usec_t r[2] = { 0, 0 };
1870
1871        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1872
1873        *min_latency = r[0];
1874        *max_latency = r[1];
1875    } else {
1876        *min_latency = s->thread_info.min_latency;
1877        *max_latency = s->thread_info.max_latency;
1878    }
1879 }
1880
1881 /* Called from IO thread */
1882 void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1883     pa_sink_input *i;
1884     void *state = NULL;
1885
1886     pa_sink_assert_ref(s);
1887
1888     pa_assert(!min_latency || !max_latency ||
1889               min_latency <= max_latency);
1890
1891     s->thread_info.min_latency = min_latency;
1892     s->thread_info.max_latency = max_latency;
1893
1894     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1895         if (i->update_sink_latency_range)
1896             i->update_sink_latency_range(i);
1897
1898     pa_sink_invalidate_requested_latency(s);
1899
1900     pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
1901 }
1902
1903 /* Called from main context */
1904 size_t pa_sink_get_max_rewind(pa_sink *s) {
1905     size_t r;
1906     pa_sink_assert_ref(s);
1907
1908     if (!PA_SINK_IS_LINKED(s->state))
1909         return s->thread_info.max_rewind;
1910
1911     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1912
1913     return r;
1914 }
1915
1916 /* Called from main context */
1917 size_t pa_sink_get_max_request(pa_sink *s) {
1918     size_t r;
1919     pa_sink_assert_ref(s);
1920
1921     if (!PA_SINK_IS_LINKED(s->state))
1922         return s->thread_info.max_request;
1923
1924     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1925
1926     return r;
1927 }
1928
1929 /* Called from main context */
1930 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
1931     const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
1932
1933     pa_assert(p);
1934
1935     if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
1936         return TRUE;
1937
1938     if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
1939
1940         if (pa_streq(ff, "microphone"))
1941             t = "audio-input-microphone";
1942         else if (pa_streq(ff, "webcam"))
1943             t = "camera-web";
1944         else if (pa_streq(ff, "computer"))
1945             t = "computer";
1946         else if (pa_streq(ff, "handset"))
1947             t = "phone";
1948         else if (pa_streq(ff, "portable"))
1949             t = "multimedia-player";
1950         else if (pa_streq(ff, "tv"))
1951             t = "video-display";
1952     }
1953
1954     if (!t)
1955         if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
1956             if (pa_streq(c, "modem"))
1957                 t = "modem";
1958
1959     if (!t) {
1960         if (is_sink)
1961             t = "audio-card";
1962         else
1963             t = "audio-input-microphone";
1964     }
1965
1966     if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
1967         if (strstr(profile, "analog"))
1968             s = "-analog";
1969         else if (strstr(profile, "iec958"))
1970             s = "-iec958";
1971         else if (strstr(profile, "hdmi"))
1972             s = "-hdmi";
1973     }
1974
1975     bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
1976
1977     pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
1978
1979     return TRUE;
1980 }
1981
1982 pa_bool_t pa_device_init_description(pa_proplist *p) {
1983     const char *s;
1984     pa_assert(p);
1985
1986     if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
1987         return TRUE;
1988
1989     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
1990         if (pa_streq(s, "internal")) {
1991             pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
1992             return TRUE;
1993         }
1994
1995     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
1996         if (pa_streq(s, "modem")) {
1997             pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
1998             return TRUE;
1999         }
2000
2001     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
2002         pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
2003         return TRUE;
2004     }
2005
2006     return FALSE;
2007 }