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