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