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