Sending translation for Finnish
[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 main thread */
962 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
963     pa_sink_input *i;
964     uint32_t idx;
965
966     pa_sink_assert_ref(s);
967     pa_assert(new_volume);
968     pa_assert(PA_SINK_IS_LINKED(s->state));
969     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
970
971     /* This is called whenever a sink input volume changes and we
972      * might need to fix up the sink volume accordingly. Please note
973      * that we don't actually update the sinks volume here, we only
974      * return how it needs to be updated. The caller should then call
975      * pa_sink_set_flat_volume().*/
976
977     if (pa_idxset_isempty(s->inputs)) {
978         /* In the special case that we have no sink input we leave the
979          * volume unmodified. */
980         *new_volume = s->virtual_volume;
981         return;
982     }
983
984     pa_cvolume_mute(new_volume, s->channel_map.channels);
985
986     /* First let's determine the new maximum volume of all inputs
987      * connected to this sink */
988     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
989         unsigned c;
990         pa_cvolume remapped_volume;
991
992         remapped_volume = i->virtual_volume;
993         pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
994
995         for (c = 0; c < new_volume->channels; c++)
996             if (remapped_volume.values[c] > new_volume->values[c])
997                 new_volume->values[c] = remapped_volume.values[c];
998     }
999
1000     /* Then, let's update the soft volumes of all inputs connected
1001      * to this sink */
1002     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1003         pa_cvolume remapped_new_volume;
1004
1005         remapped_new_volume = *new_volume;
1006         pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1007         pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
1008         pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor);
1009
1010         /* Hooks have the ability to play games with i->soft_volume */
1011         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1012
1013         /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
1014          * we want the update to have atomically with the sink
1015          * volume update, hence we do it within the
1016          * pa_sink_set_flat_volume() call below*/
1017     }
1018 }
1019
1020 /* Called from main thread */
1021 void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
1022     pa_sink_input *i;
1023     uint32_t idx;
1024
1025     pa_sink_assert_ref(s);
1026     pa_assert(old_volume);
1027     pa_assert(PA_SINK_IS_LINKED(s->state));
1028     pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1029
1030     /* This is called whenever the sink volume changes that is not
1031      * caused by a sink input volume change. We need to fix up the
1032      * sink input volumes accordingly */
1033
1034     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1035         pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
1036         unsigned c;
1037
1038         remapped_new_volume = s->virtual_volume;
1039         pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1040
1041         remapped_old_volume = *old_volume;
1042         pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
1043
1044         for (c = 0; c < i->sample_spec.channels; c++)
1045
1046             if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
1047                 fixed_volume.values[c] = PA_VOLUME_MUTED;
1048             else
1049                 fixed_volume.values[c] = (pa_volume_t)
1050                     ((uint64_t) i->virtual_volume.values[c] *
1051                      (uint64_t) remapped_new_volume.values[c] /
1052                      (uint64_t) remapped_old_volume.values[c]);
1053
1054         fixed_volume.channels = i->virtual_volume.channels;
1055
1056         if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
1057             i->virtual_volume = fixed_volume;
1058
1059             /* The virtual volume changed, let's tell people so */
1060             pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1061         }
1062     }
1063 }
1064
1065 /* Called from main thread */
1066 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1067     pa_cvolume old_virtual_volume;
1068     pa_bool_t virtual_volume_changed;
1069
1070     pa_sink_assert_ref(s);
1071     pa_assert(PA_SINK_IS_LINKED(s->state));
1072     pa_assert(volume);
1073     pa_assert(pa_cvolume_valid(volume));
1074     pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1075
1076     old_virtual_volume = s->virtual_volume;
1077     s->virtual_volume = *volume;
1078     virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
1079
1080     /* Propagate this volume change back to the inputs */
1081     if (virtual_volume_changed)
1082         if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1083             pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1084
1085     if (s->set_volume) {
1086         /* If we have a function set_volume(), then we do not apply a
1087          * soft volume by default. However, set_volume() is apply one
1088          * to s->soft_volume */
1089
1090         pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1091         s->set_volume(s);
1092
1093     } else
1094         /* If we have no function set_volume(), then the soft volume
1095          * becomes the virtual volume */
1096         s->soft_volume = s->virtual_volume;
1097
1098     /* This tells the sink that soft and/or virtual volume changed */
1099     if (sendmsg)
1100         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1101
1102     if (virtual_volume_changed)
1103         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1104 }
1105
1106 /* Called from main thread. Only to be called by sink implementor */
1107 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1108     pa_sink_assert_ref(s);
1109     pa_assert(volume);
1110
1111     s->soft_volume = *volume;
1112
1113     if (PA_SINK_IS_LINKED(s->state))
1114         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1115     else
1116         s->thread_info.soft_volume = *volume;
1117 }
1118
1119 /* Called from main thread */
1120 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1121     pa_sink_assert_ref(s);
1122
1123     if (s->refresh_volume || force_refresh) {
1124         struct pa_cvolume old_virtual_volume = s->virtual_volume;
1125
1126         if (s->get_volume)
1127             s->get_volume(s);
1128
1129         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1130
1131         if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1132
1133             if (s->flags & PA_SINK_FLAT_VOLUME)
1134                 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1135
1136             pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1137         }
1138     }
1139
1140     return &s->virtual_volume;
1141 }
1142
1143 /* Called from main thread */
1144 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
1145     pa_sink_assert_ref(s);
1146
1147     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1148
1149     if (pa_cvolume_equal(&s->virtual_volume, new_volume))
1150         return;
1151
1152     s->virtual_volume = *new_volume;
1153     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1154 }
1155
1156 /* Called from main thread */
1157 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1158     pa_bool_t old_muted;
1159
1160     pa_sink_assert_ref(s);
1161     pa_assert(PA_SINK_IS_LINKED(s->state));
1162
1163     old_muted = s->muted;
1164     s->muted = mute;
1165
1166     if (s->set_mute)
1167         s->set_mute(s);
1168
1169     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1170
1171     if (old_muted != s->muted)
1172         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1173 }
1174
1175 /* Called from main thread */
1176 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1177
1178     pa_sink_assert_ref(s);
1179
1180     if (s->refresh_muted || force_refresh) {
1181         pa_bool_t old_muted = s->muted;
1182
1183         if (s->get_mute)
1184             s->get_mute(s);
1185
1186         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1187
1188         if (old_muted != s->muted)
1189             pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1190     }
1191
1192     return s->muted;
1193 }
1194
1195 /* Called from main thread */
1196 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
1197     pa_sink_assert_ref(s);
1198
1199     /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1200
1201     if (s->muted == new_muted)
1202         return;
1203
1204     s->muted = new_muted;
1205     pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1206 }
1207
1208 /* Called from main thread */
1209 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1210     pa_sink_assert_ref(s);
1211
1212     if (p)
1213         pa_proplist_update(s->proplist, mode, p);
1214
1215     if (PA_SINK_IS_LINKED(s->state)) {
1216         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1217         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1218     }
1219
1220     return TRUE;
1221 }
1222
1223 /* Called from main thread */
1224 void pa_sink_set_description(pa_sink *s, const char *description) {
1225     const char *old;
1226     pa_sink_assert_ref(s);
1227
1228     if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1229         return;
1230
1231     old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1232
1233     if (old && description && !strcmp(old, description))
1234         return;
1235
1236     if (description)
1237         pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1238     else
1239         pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1240
1241     if (s->monitor_source) {
1242         char *n;
1243
1244         n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1245         pa_source_set_description(s->monitor_source, n);
1246         pa_xfree(n);
1247     }
1248
1249     if (PA_SINK_IS_LINKED(s->state)) {
1250         pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1251         pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1252     }
1253 }
1254
1255 /* Called from main thread */
1256 unsigned pa_sink_linked_by(pa_sink *s) {
1257     unsigned ret;
1258
1259     pa_sink_assert_ref(s);
1260     pa_assert(PA_SINK_IS_LINKED(s->state));
1261
1262     ret = pa_idxset_size(s->inputs);
1263
1264     /* We add in the number of streams connected to us here. Please
1265      * note the asymmmetry to pa_sink_used_by()! */
1266
1267     if (s->monitor_source)
1268         ret += pa_source_linked_by(s->monitor_source);
1269
1270     return ret;
1271 }
1272
1273 /* Called from main thread */
1274 unsigned pa_sink_used_by(pa_sink *s) {
1275     unsigned ret;
1276
1277     pa_sink_assert_ref(s);
1278     pa_assert(PA_SINK_IS_LINKED(s->state));
1279
1280     ret = pa_idxset_size(s->inputs);
1281     pa_assert(ret >= s->n_corked);
1282
1283     /* Streams connected to our monitor source do not matter for
1284      * pa_sink_used_by()!.*/
1285
1286     return ret - s->n_corked;
1287 }
1288
1289 /* Called from main thread */
1290 unsigned pa_sink_check_suspend(pa_sink *s) {
1291     unsigned ret;
1292     pa_sink_input *i;
1293     uint32_t idx;
1294
1295     pa_sink_assert_ref(s);
1296
1297     if (!PA_SINK_IS_LINKED(s->state))
1298         return 0;
1299
1300     ret = 0;
1301
1302     for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1303         pa_sink_input_state_t st;
1304
1305         st = pa_sink_input_get_state(i);
1306         pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1307
1308         if (st == PA_SINK_INPUT_CORKED)
1309             continue;
1310
1311         if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1312             continue;
1313
1314         ret ++;
1315     }
1316
1317     if (s->monitor_source)
1318         ret += pa_source_check_suspend(s->monitor_source);
1319
1320     return ret;
1321 }
1322
1323 /* Called from the IO thread */
1324 static void sync_input_volumes_within_thread(pa_sink *s) {
1325     pa_sink_input *i;
1326     void *state = NULL;
1327
1328     pa_sink_assert_ref(s);
1329
1330     while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1331         if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1332             continue;
1333
1334         i->thread_info.soft_volume = i->soft_volume;
1335         pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1336     }
1337 }
1338
1339 /* Called from IO thread, except when it is not */
1340 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1341     pa_sink *s = PA_SINK(o);
1342     pa_sink_assert_ref(s);
1343
1344     switch ((pa_sink_message_t) code) {
1345
1346         case PA_SINK_MESSAGE_ADD_INPUT: {
1347             pa_sink_input *i = PA_SINK_INPUT(userdata);
1348
1349             /* If you change anything here, make sure to change the
1350              * sink input handling a few lines down at
1351              * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1352
1353             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1354
1355             /* Since the caller sleeps in pa_sink_input_put(), we can
1356              * safely access data outside of thread_info even though
1357              * it is mutable */
1358
1359             if ((i->thread_info.sync_prev = i->sync_prev)) {
1360                 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1361                 pa_assert(i->sync_prev->sync_next == i);
1362                 i->thread_info.sync_prev->thread_info.sync_next = i;
1363             }
1364
1365             if ((i->thread_info.sync_next = i->sync_next)) {
1366                 pa_assert(i->sink == i->thread_info.sync_next->sink);
1367                 pa_assert(i->sync_next->sync_prev == i);
1368                 i->thread_info.sync_next->thread_info.sync_prev = i;
1369             }
1370
1371             pa_assert(!i->thread_info.attached);
1372             i->thread_info.attached = TRUE;
1373
1374             if (i->attach)
1375                 i->attach(i);
1376
1377             pa_sink_input_set_state_within_thread(i, i->state);
1378
1379             /* The requested latency of the sink input needs to be
1380              * fixed up and then configured on the sink */
1381
1382             if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1383                 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1384
1385             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1386             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1387
1388             /* We don't rewind here automatically. This is left to the
1389              * sink input implementor because some sink inputs need a
1390              * slow start, i.e. need some time to buffer client
1391              * samples before beginning streaming. */
1392
1393             /* In flat volume mode we need to update the volume as
1394              * well */
1395             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1396         }
1397
1398         case PA_SINK_MESSAGE_REMOVE_INPUT: {
1399             pa_sink_input *i = PA_SINK_INPUT(userdata);
1400
1401             /* If you change anything here, make sure to change the
1402              * sink input handling a few lines down at
1403              * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1404
1405             if (i->detach)
1406                 i->detach(i);
1407
1408             pa_sink_input_set_state_within_thread(i, i->state);
1409
1410             pa_assert(i->thread_info.attached);
1411             i->thread_info.attached = FALSE;
1412
1413             /* Since the caller sleeps in pa_sink_input_unlink(),
1414              * we can safely access data outside of thread_info even
1415              * though it is mutable */
1416
1417             pa_assert(!i->sync_prev);
1418             pa_assert(!i->sync_next);
1419
1420             if (i->thread_info.sync_prev) {
1421                 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1422                 i->thread_info.sync_prev = NULL;
1423             }
1424
1425             if (i->thread_info.sync_next) {
1426                 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1427                 i->thread_info.sync_next = NULL;
1428             }
1429
1430             if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1431                 pa_sink_input_unref(i);
1432
1433             pa_sink_invalidate_requested_latency(s);
1434             pa_sink_request_rewind(s, (size_t) -1);
1435
1436             /* In flat volume mode we need to update the volume as
1437              * well */
1438             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1439         }
1440
1441         case PA_SINK_MESSAGE_START_MOVE: {
1442             pa_sink_input *i = PA_SINK_INPUT(userdata);
1443
1444             /* We don't support moving synchronized streams. */
1445             pa_assert(!i->sync_prev);
1446             pa_assert(!i->sync_next);
1447             pa_assert(!i->thread_info.sync_next);
1448             pa_assert(!i->thread_info.sync_prev);
1449
1450             if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1451                 pa_usec_t usec = 0;
1452                 size_t sink_nbytes, total_nbytes;
1453
1454                 /* Get the latency of the sink */
1455                 if (!(s->flags & PA_SINK_LATENCY) ||
1456                     PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1457                     usec = 0;
1458
1459                 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1460                 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1461
1462                 if (total_nbytes > 0) {
1463                     i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1464                     i->thread_info.rewrite_flush = TRUE;
1465                     pa_sink_input_process_rewind(i, sink_nbytes);
1466                 }
1467             }
1468
1469             if (i->detach)
1470                 i->detach(i);
1471
1472             pa_assert(i->thread_info.attached);
1473             i->thread_info.attached = FALSE;
1474
1475             /* Let's remove the sink input ...*/
1476             if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1477                 pa_sink_input_unref(i);
1478
1479             pa_sink_invalidate_requested_latency(s);
1480
1481             pa_log_debug("Requesting rewind due to started move");
1482             pa_sink_request_rewind(s, (size_t) -1);
1483
1484             /* In flat volume mode we need to update the volume as
1485              * well */
1486             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1487         }
1488
1489         case PA_SINK_MESSAGE_FINISH_MOVE: {
1490             pa_sink_input *i = PA_SINK_INPUT(userdata);
1491
1492             /* We don't support moving synchronized streams. */
1493             pa_assert(!i->sync_prev);
1494             pa_assert(!i->sync_next);
1495             pa_assert(!i->thread_info.sync_next);
1496             pa_assert(!i->thread_info.sync_prev);
1497
1498             pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1499
1500             pa_assert(!i->thread_info.attached);
1501             i->thread_info.attached = TRUE;
1502
1503             if (i->attach)
1504                 i->attach(i);
1505
1506             if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1507                 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1508
1509             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1510             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1511
1512             if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1513                 pa_usec_t usec = 0;
1514                 size_t nbytes;
1515
1516                 /* Get the latency of the sink */
1517                 if (!(s->flags & PA_SINK_LATENCY) ||
1518                     PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1519                     usec = 0;
1520
1521                 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1522
1523                 if (nbytes > 0)
1524                     pa_sink_input_drop(i, nbytes);
1525
1526                 pa_log_debug("Requesting rewind due to finished move");
1527                 pa_sink_request_rewind(s, nbytes);
1528             }
1529
1530             /* In flat volume mode we need to update the volume as
1531              * well */
1532             return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1533         }
1534
1535         case PA_SINK_MESSAGE_SET_VOLUME:
1536
1537             if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1538                 s->thread_info.soft_volume = s->soft_volume;
1539                 pa_sink_request_rewind(s, (size_t) -1);
1540             }
1541
1542             if (s->flags & PA_SINK_FLAT_VOLUME)
1543                 sync_input_volumes_within_thread(s);
1544
1545             return 0;
1546
1547         case PA_SINK_MESSAGE_GET_VOLUME:
1548             return 0;
1549
1550         case PA_SINK_MESSAGE_SET_MUTE:
1551
1552             if (s->thread_info.soft_muted != s->muted) {
1553                 s->thread_info.soft_muted = s->muted;
1554                 pa_sink_request_rewind(s, (size_t) -1);
1555             }
1556
1557             return 0;
1558
1559         case PA_SINK_MESSAGE_GET_MUTE:
1560             return 0;
1561
1562         case PA_SINK_MESSAGE_SET_STATE:
1563
1564             s->thread_info.state = PA_PTR_TO_UINT(userdata);
1565
1566             if (s->thread_info.state == PA_SINK_SUSPENDED) {
1567                 s->thread_info.rewind_nbytes = 0;
1568                 s->thread_info.rewind_requested = FALSE;
1569             }
1570
1571             return 0;
1572
1573         case PA_SINK_MESSAGE_DETACH:
1574
1575             /* Detach all streams */
1576             pa_sink_detach_within_thread(s);
1577             return 0;
1578
1579         case PA_SINK_MESSAGE_ATTACH:
1580
1581             /* Reattach all streams */
1582             pa_sink_attach_within_thread(s);
1583             return 0;
1584
1585         case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1586
1587             pa_usec_t *usec = userdata;
1588             *usec = pa_sink_get_requested_latency_within_thread(s);
1589
1590             if (*usec == (pa_usec_t) -1)
1591                 *usec = s->thread_info.max_latency;
1592
1593             return 0;
1594         }
1595
1596         case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1597             pa_usec_t *r = userdata;
1598
1599             pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
1600
1601             return 0;
1602         }
1603
1604         case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1605             pa_usec_t *r = userdata;
1606
1607             r[0] = s->thread_info.min_latency;
1608             r[1] = s->thread_info.max_latency;
1609
1610             return 0;
1611         }
1612
1613         case PA_SINK_MESSAGE_GET_MAX_REWIND:
1614
1615             *((size_t*) userdata) = s->thread_info.max_rewind;
1616             return 0;
1617
1618         case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1619
1620             *((size_t*) userdata) = s->thread_info.max_request;
1621             return 0;
1622
1623         case PA_SINK_MESSAGE_SET_MAX_REWIND:
1624
1625             pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
1626             return 0;
1627
1628         case PA_SINK_MESSAGE_SET_MAX_REQUEST:
1629
1630             pa_sink_set_max_request_within_thread(s, (size_t) offset);
1631             return 0;
1632
1633         case PA_SINK_MESSAGE_GET_LATENCY:
1634         case PA_SINK_MESSAGE_MAX:
1635             ;
1636     }
1637
1638     return -1;
1639 }
1640
1641 /* Called from main thread */
1642 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1643     pa_sink *sink;
1644     uint32_t idx;
1645     int ret = 0;
1646
1647     pa_core_assert_ref(c);
1648
1649     for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1650         int r;
1651
1652         if ((r = pa_sink_suspend(sink, suspend)) < 0)
1653             ret = r;
1654     }
1655
1656     return ret;
1657 }
1658
1659 /* Called from main thread */
1660 void pa_sink_detach(pa_sink *s) {
1661     pa_sink_assert_ref(s);
1662     pa_assert(PA_SINK_IS_LINKED(s->state));
1663
1664     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1665 }
1666
1667 /* Called from main thread */
1668 void pa_sink_attach(pa_sink *s) {
1669     pa_sink_assert_ref(s);
1670     pa_assert(PA_SINK_IS_LINKED(s->state));
1671
1672     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1673 }
1674
1675 /* Called from IO thread */
1676 void pa_sink_detach_within_thread(pa_sink *s) {
1677     pa_sink_input *i;
1678     void *state = NULL;
1679
1680     pa_sink_assert_ref(s);
1681     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1682
1683     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1684         if (i->detach)
1685             i->detach(i);
1686
1687     if (s->monitor_source)
1688         pa_source_detach_within_thread(s->monitor_source);
1689 }
1690
1691 /* Called from IO thread */
1692 void pa_sink_attach_within_thread(pa_sink *s) {
1693     pa_sink_input *i;
1694     void *state = NULL;
1695
1696     pa_sink_assert_ref(s);
1697     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1698
1699     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1700         if (i->attach)
1701             i->attach(i);
1702
1703     if (s->monitor_source)
1704         pa_source_attach_within_thread(s->monitor_source);
1705 }
1706
1707 /* Called from IO thread */
1708 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1709     pa_sink_assert_ref(s);
1710     pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1711
1712     if (s->thread_info.state == PA_SINK_SUSPENDED)
1713         return;
1714
1715     if (nbytes == (size_t) -1)
1716         nbytes = s->thread_info.max_rewind;
1717
1718     nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1719
1720     if (s->thread_info.rewind_requested &&
1721         nbytes <= s->thread_info.rewind_nbytes)
1722         return;
1723
1724     s->thread_info.rewind_nbytes = nbytes;
1725     s->thread_info.rewind_requested = TRUE;
1726
1727     if (s->request_rewind)
1728         s->request_rewind(s);
1729 }
1730
1731 /* Called from IO thread */
1732 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1733     pa_usec_t result = (pa_usec_t) -1;
1734     pa_sink_input *i;
1735     void *state = NULL;
1736     pa_usec_t monitor_latency;
1737
1738     pa_sink_assert_ref(s);
1739
1740     if (s->thread_info.requested_latency_valid)
1741         return s->thread_info.requested_latency;
1742
1743     while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1744
1745         if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1746             (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1747             result = i->thread_info.requested_sink_latency;
1748
1749     monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1750
1751     if (monitor_latency != (pa_usec_t) -1 &&
1752         (result == (pa_usec_t) -1 || result > monitor_latency))
1753         result = monitor_latency;
1754
1755     if (result != (pa_usec_t) -1) {
1756         if (result > s->thread_info.max_latency)
1757             result = s->thread_info.max_latency;
1758
1759         if (result < s->thread_info.min_latency)
1760             result = s->thread_info.min_latency;
1761     }
1762
1763     s->thread_info.requested_latency = result;
1764     s->thread_info.requested_latency_valid = TRUE;
1765
1766     return result;
1767 }
1768
1769 /* Called from main thread */
1770 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1771     pa_usec_t usec = 0;
1772
1773     pa_sink_assert_ref(s);
1774     pa_assert(PA_SINK_IS_LINKED(s->state));
1775
1776     if (s->state == PA_SINK_SUSPENDED)
1777         return 0;
1778
1779     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1780     return usec;
1781 }
1782
1783 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1784 void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
1785     pa_sink_input *i;
1786     void *state = NULL;
1787
1788     pa_sink_assert_ref(s);
1789
1790     if (max_rewind == s->thread_info.max_rewind)
1791         return;
1792
1793     s->thread_info.max_rewind = max_rewind;
1794
1795     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1796         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1797             pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1798     }
1799
1800     if (s->monitor_source)
1801         pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
1802 }
1803
1804 /* Called from main thread */
1805 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1806     pa_sink_assert_ref(s);
1807
1808     if (PA_SINK_IS_LINKED(s->state))
1809         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1810     else
1811         pa_sink_set_max_rewind_within_thread(s, max_rewind);
1812 }
1813
1814 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1815 void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
1816     void *state = NULL;
1817
1818     pa_sink_assert_ref(s);
1819
1820     if (max_request == s->thread_info.max_request)
1821         return;
1822
1823     s->thread_info.max_request = max_request;
1824
1825     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1826         pa_sink_input *i;
1827
1828         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1829             pa_sink_input_update_max_request(i, s->thread_info.max_request);
1830     }
1831 }
1832
1833 /* Called from main thread */
1834 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1835     pa_sink_assert_ref(s);
1836
1837     if (PA_SINK_IS_LINKED(s->state))
1838         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
1839     else
1840         pa_sink_set_max_request_within_thread(s, max_request);
1841 }
1842
1843 /* Called from IO thread */
1844 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1845     pa_sink_input *i;
1846     void *state = NULL;
1847
1848     pa_sink_assert_ref(s);
1849
1850     s->thread_info.requested_latency_valid = FALSE;
1851
1852     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1853
1854         if (s->update_requested_latency)
1855             s->update_requested_latency(s);
1856
1857         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1858             if (i->update_sink_requested_latency)
1859                 i->update_sink_requested_latency(i);
1860     }
1861 }
1862
1863 /* Called from main thread */
1864 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1865     pa_sink_assert_ref(s);
1866
1867     /* min_latency == 0:           no limit
1868      * min_latency anything else:  specified limit
1869      *
1870      * Similar for max_latency */
1871
1872     if (min_latency < ABSOLUTE_MIN_LATENCY)
1873         min_latency = ABSOLUTE_MIN_LATENCY;
1874
1875     if (max_latency <= 0 ||
1876         max_latency > ABSOLUTE_MAX_LATENCY)
1877         max_latency = ABSOLUTE_MAX_LATENCY;
1878
1879     pa_assert(min_latency <= max_latency);
1880
1881     /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
1882     pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1883                max_latency == ABSOLUTE_MAX_LATENCY) ||
1884               (s->flags & PA_SINK_DYNAMIC_LATENCY));
1885
1886     if (PA_SINK_IS_LINKED(s->state)) {
1887         pa_usec_t r[2];
1888
1889         r[0] = min_latency;
1890         r[1] = max_latency;
1891
1892         pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1893     } else
1894         pa_sink_set_latency_range_within_thread(s, min_latency, max_latency);
1895 }
1896
1897 /* Called from main thread */
1898 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1899    pa_sink_assert_ref(s);
1900    pa_assert(min_latency);
1901    pa_assert(max_latency);
1902
1903    if (PA_SINK_IS_LINKED(s->state)) {
1904        pa_usec_t r[2] = { 0, 0 };
1905
1906        pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1907
1908        *min_latency = r[0];
1909        *max_latency = r[1];
1910    } else {
1911        *min_latency = s->thread_info.min_latency;
1912        *max_latency = s->thread_info.max_latency;
1913    }
1914 }
1915
1916 /* Called from IO thread */
1917 void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1918     void *state = NULL;
1919
1920     pa_sink_assert_ref(s);
1921
1922     pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1923     pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1924     pa_assert(min_latency <= max_latency);
1925
1926     /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
1927     pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
1928                max_latency == ABSOLUTE_MAX_LATENCY) ||
1929               (s->flags & PA_SINK_DYNAMIC_LATENCY));
1930
1931     s->thread_info.min_latency = min_latency;
1932     s->thread_info.max_latency = max_latency;
1933
1934     if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1935         pa_sink_input *i;
1936
1937         while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1938             if (i->update_sink_latency_range)
1939                 i->update_sink_latency_range(i);
1940     }
1941
1942     pa_sink_invalidate_requested_latency(s);
1943
1944     pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
1945 }
1946
1947 /* Called from main context */
1948 size_t pa_sink_get_max_rewind(pa_sink *s) {
1949     size_t r;
1950     pa_sink_assert_ref(s);
1951
1952     if (!PA_SINK_IS_LINKED(s->state))
1953         return s->thread_info.max_rewind;
1954
1955     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1956
1957     return r;
1958 }
1959
1960 /* Called from main context */
1961 size_t pa_sink_get_max_request(pa_sink *s) {
1962     size_t r;
1963     pa_sink_assert_ref(s);
1964
1965     if (!PA_SINK_IS_LINKED(s->state))
1966         return s->thread_info.max_request;
1967
1968     pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1969
1970     return r;
1971 }
1972
1973 /* Called from main context */
1974 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
1975     const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
1976
1977     pa_assert(p);
1978
1979     if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
1980         return TRUE;
1981
1982     if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
1983
1984         if (pa_streq(ff, "microphone"))
1985             t = "audio-input-microphone";
1986         else if (pa_streq(ff, "webcam"))
1987             t = "camera-web";
1988         else if (pa_streq(ff, "computer"))
1989             t = "computer";
1990         else if (pa_streq(ff, "handset"))
1991             t = "phone";
1992         else if (pa_streq(ff, "portable"))
1993             t = "multimedia-player";
1994         else if (pa_streq(ff, "tv"))
1995             t = "video-display";
1996     }
1997
1998     if (!t)
1999         if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2000             if (pa_streq(c, "modem"))
2001                 t = "modem";
2002
2003     if (!t) {
2004         if (is_sink)
2005             t = "audio-card";
2006         else
2007             t = "audio-input-microphone";
2008     }
2009
2010     if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
2011         if (strstr(profile, "analog"))
2012             s = "-analog";
2013         else if (strstr(profile, "iec958"))
2014             s = "-iec958";
2015         else if (strstr(profile, "hdmi"))
2016             s = "-hdmi";
2017     }
2018
2019     bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
2020
2021     pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
2022
2023     return TRUE;
2024 }
2025
2026 pa_bool_t pa_device_init_description(pa_proplist *p) {
2027     const char *s;
2028     pa_assert(p);
2029
2030     if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
2031         return TRUE;
2032
2033     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
2034         if (pa_streq(s, "internal")) {
2035             pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
2036             return TRUE;
2037         }
2038
2039     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2040         if (pa_streq(s, "modem")) {
2041             pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
2042             return TRUE;
2043         }
2044
2045     if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
2046         pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
2047         return TRUE;
2048     }
2049
2050     return FALSE;
2051 }