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