Use LGPL 2.1 on all files previously using LGPL 2
[pulseaudio-mirror.git] / src / pulsecore / sink.c
blob298cc88141e3e2f0dea345499da08eb9d30b6a18
1 /***
2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
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.
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.
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 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
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>
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>
47 #include "sink.h"
49 #define MAX_MIX_CHANNELS 32
50 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
51 #define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
53 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
55 static void sink_free(pa_object *s);
57 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
58 pa_assert(data);
60 memset(data, 0, sizeof(*data));
61 data->proplist = pa_proplist_new();
63 return data;
66 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
67 pa_assert(data);
69 pa_xfree(data->name);
70 data->name = pa_xstrdup(name);
73 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
74 pa_assert(data);
76 if ((data->sample_spec_is_set = !!spec))
77 data->sample_spec = *spec;
80 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
81 pa_assert(data);
83 if ((data->channel_map_is_set = !!map))
84 data->channel_map = *map;
87 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
88 pa_assert(data);
90 if ((data->volume_is_set = !!volume))
91 data->volume = *volume;
94 void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
95 pa_assert(data);
97 data->muted_is_set = TRUE;
98 data->muted = !!mute;
101 void pa_sink_new_data_done(pa_sink_new_data *data) {
102 pa_assert(data);
104 pa_xfree(data->name);
105 pa_proplist_free(data->proplist);
108 /* Called from main context */
109 static void reset_callbacks(pa_sink *s) {
110 pa_assert(s);
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;
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) {
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;
134 pa_assert(core);
135 pa_assert(data);
136 pa_assert(data->name);
138 s = pa_msgobject_new(pa_sink);
140 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
141 pa_xfree(s);
142 return NULL;
145 pa_sink_new_data_set_name(data, name);
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;
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]);
156 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
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));
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);
164 if (!data->volume_is_set)
165 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
167 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
168 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
170 if (!data->muted_is_set)
171 data->muted = FALSE;
173 if (data->card)
174 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
176 pa_device_init_description(data->proplist);
177 pa_device_init_icon(data->proplist, TRUE);
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;
185 s->parent.parent.free = sink_free;
186 s->parent.process_msg = pa_sink_process_msg;
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;
197 s->sample_spec = data->sample_spec;
198 s->channel_map = data->channel_map;
200 s->inputs = pa_idxset_new(NULL, NULL);
201 s->n_corked = 0;
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;
210 reset_callbacks(s);
211 s->userdata = NULL;
213 s->asyncmsgq = NULL;
214 s->rtpoll = NULL;
216 pa_silence_memchunk_get(
217 &core->silence_cache,
218 core->mempool,
219 &s->silence,
220 &s->sample_spec,
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;
236 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
238 if (s->card)
239 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
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);
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;
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");
262 s->monitor_source = pa_source_new(core, &source_data, PA_SOURCE_LATENCY);
264 pa_source_new_data_done(&source_data);
266 if (!s->monitor_source) {
267 pa_sink_unlink(s);
268 pa_sink_unref(s);
269 return NULL;
272 s->monitor_source->monitor_of = s;
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);
277 return s;
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;
286 pa_assert(s);
288 if (s->state == state)
289 return 0;
291 original_state = s->state;
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);
297 if (s->set_state)
298 if ((ret = s->set_state(s, state)) < 0)
299 return ret;
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) {
304 if (s->set_state)
305 s->set_state(s, original_state);
307 return ret;
310 s->state = state;
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);
317 if (suspend_change) {
318 pa_sink_input *i;
319 uint32_t idx;
321 /* We're suspending or resuming, tell everyone about it */
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);
331 return 0;
334 /* Called from main context */
335 void pa_sink_put(pa_sink* s) {
336 pa_sink_assert_ref(s);
338 pa_assert(s->state == PA_SINK_INIT);
340 /* The following fields must be initialized properly when calling _put() */
341 pa_assert(s->asyncmsgq);
342 pa_assert(s->rtpoll);
343 pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
344 s->thread_info.min_latency <= s->thread_info.max_latency);
346 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
347 s->flags |= PA_SINK_DECIBEL_VOLUME;
349 s->thread_info.soft_volume = s->soft_volume;
350 s->thread_info.soft_muted = s->muted;
353 if (s->flags & PA_SINK_DECIBEL_VOLUME)
354 s->n_volume_steps = PA_VOLUME_NORM+1;
356 if (s->core->flat_volumes)
357 if (s->flags & PA_SINK_DECIBEL_VOLUME)
358 s->flags |= PA_SINK_FLAT_VOLUME;
360 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
362 pa_source_put(s->monitor_source);
364 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
365 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
368 /* Called from main context */
369 void pa_sink_unlink(pa_sink* s) {
370 pa_bool_t linked;
371 pa_sink_input *i, *j = NULL;
373 pa_assert(s);
375 /* Please note that pa_sink_unlink() does more than simply
376 * reversing pa_sink_put(). It also undoes the registrations
377 * already done in pa_sink_new()! */
379 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
380 * may be called multiple times on the same sink without bad
381 * effects. */
383 linked = PA_SINK_IS_LINKED(s->state);
385 if (linked)
386 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
388 if (s->state != PA_SINK_UNLINKED)
389 pa_namereg_unregister(s->core, s->name);
390 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
392 if (s->card)
393 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
395 while ((i = pa_idxset_first(s->inputs, NULL))) {
396 pa_assert(i != j);
397 pa_sink_input_kill(i);
398 j = i;
401 if (linked)
402 sink_set_state(s, PA_SINK_UNLINKED);
403 else
404 s->state = PA_SINK_UNLINKED;
406 reset_callbacks(s);
408 if (s->monitor_source)
409 pa_source_unlink(s->monitor_source);
411 if (linked) {
412 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
413 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
417 /* Called from main context */
418 static void sink_free(pa_object *o) {
419 pa_sink *s = PA_SINK(o);
420 pa_sink_input *i;
422 pa_assert(s);
423 pa_assert(pa_sink_refcnt(s) == 0);
425 if (PA_SINK_IS_LINKED(s->state))
426 pa_sink_unlink(s);
428 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
430 if (s->monitor_source) {
431 pa_source_unref(s->monitor_source);
432 s->monitor_source = NULL;
435 pa_idxset_free(s->inputs, NULL, NULL);
437 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
438 pa_sink_input_unref(i);
440 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
442 if (s->silence.memblock)
443 pa_memblock_unref(s->silence.memblock);
445 pa_xfree(s->name);
446 pa_xfree(s->driver);
448 if (s->proplist)
449 pa_proplist_free(s->proplist);
451 pa_xfree(s);
454 /* Called from main context */
455 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
456 pa_sink_assert_ref(s);
458 s->asyncmsgq = q;
460 if (s->monitor_source)
461 pa_source_set_asyncmsgq(s->monitor_source, q);
464 /* Called from main context */
465 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
466 pa_sink_assert_ref(s);
468 s->rtpoll = p;
469 if (s->monitor_source)
470 pa_source_set_rtpoll(s->monitor_source, p);
473 /* Called from main context */
474 int pa_sink_update_status(pa_sink*s) {
475 pa_sink_assert_ref(s);
476 pa_assert(PA_SINK_IS_LINKED(s->state));
478 if (s->state == PA_SINK_SUSPENDED)
479 return 0;
481 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
484 /* Called from main context */
485 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
486 pa_sink_assert_ref(s);
487 pa_assert(PA_SINK_IS_LINKED(s->state));
489 if (suspend)
490 return sink_set_state(s, PA_SINK_SUSPENDED);
491 else
492 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
495 /* Called from main context */
496 pa_queue *pa_sink_move_all_start(pa_sink *s) {
497 pa_queue *q;
498 pa_sink_input *i, *n;
499 uint32_t idx;
501 pa_sink_assert_ref(s);
502 pa_assert(PA_SINK_IS_LINKED(s->state));
504 q = pa_queue_new();
506 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
507 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
509 if (pa_sink_input_start_move(i) >= 0)
510 pa_queue_push(q, pa_sink_input_ref(i));
513 return q;
516 /* Called from main context */
517 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
518 pa_sink_input *i;
520 pa_sink_assert_ref(s);
521 pa_assert(PA_SINK_IS_LINKED(s->state));
522 pa_assert(q);
524 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
525 if (pa_sink_input_finish_move(i, s, save) < 0)
526 pa_sink_input_kill(i);
528 pa_sink_input_unref(i);
531 pa_queue_free(q, NULL, NULL);
534 /* Called from main context */
535 void pa_sink_move_all_fail(pa_queue *q) {
536 pa_sink_input *i;
537 pa_assert(q);
539 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
540 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
541 pa_sink_input_kill(i);
542 pa_sink_input_unref(i);
546 pa_queue_free(q, NULL, NULL);
549 /* Called from IO thread context */
550 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
551 pa_sink_input *i;
552 void *state = NULL;
553 pa_sink_assert_ref(s);
554 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
556 /* If nobody requested this and this is actually no real rewind
557 * then we can short cut this */
558 if (!s->thread_info.rewind_requested && nbytes <= 0)
559 return;
561 s->thread_info.rewind_nbytes = 0;
562 s->thread_info.rewind_requested = FALSE;
564 if (s->thread_info.state == PA_SINK_SUSPENDED)
565 return;
567 if (nbytes > 0)
568 pa_log_debug("Processing rewind...");
570 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
571 pa_sink_input_assert_ref(i);
572 pa_sink_input_process_rewind(i, nbytes);
575 if (nbytes > 0)
576 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
577 pa_source_process_rewind(s->monitor_source, nbytes);
580 /* Called from IO thread context */
581 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
582 pa_sink_input *i;
583 unsigned n = 0;
584 void *state = NULL;
585 size_t mixlength = *length;
587 pa_sink_assert_ref(s);
588 pa_assert(info);
590 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
591 pa_sink_input_assert_ref(i);
593 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
595 if (mixlength == 0 || info->chunk.length < mixlength)
596 mixlength = info->chunk.length;
598 if (pa_memblock_is_silence(info->chunk.memblock)) {
599 pa_memblock_unref(info->chunk.memblock);
600 continue;
603 info->userdata = pa_sink_input_ref(i);
605 pa_assert(info->chunk.memblock);
606 pa_assert(info->chunk.length > 0);
608 info++;
609 n++;
610 maxinfo--;
613 if (mixlength > 0)
614 *length = mixlength;
616 return n;
619 /* Called from IO thread context */
620 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
621 pa_sink_input *i;
622 void *state = NULL;
623 unsigned p = 0;
624 unsigned n_unreffed = 0;
626 pa_sink_assert_ref(s);
627 pa_assert(result);
628 pa_assert(result->memblock);
629 pa_assert(result->length > 0);
631 /* We optimize for the case where the order of the inputs has not changed */
633 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
634 unsigned j;
635 pa_mix_info* m = NULL;
637 pa_sink_input_assert_ref(i);
639 /* Let's try to find the matching entry info the pa_mix_info array */
640 for (j = 0; j < n; j ++) {
642 if (info[p].userdata == i) {
643 m = info + p;
644 break;
647 p++;
648 if (p >= n)
649 p = 0;
652 /* Drop read data */
653 pa_sink_input_drop(i, result->length);
655 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
657 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
658 void *ostate = NULL;
659 pa_source_output *o;
660 pa_memchunk c;
662 if (m && m->chunk.memblock) {
663 c = m->chunk;
664 pa_memblock_ref(c.memblock);
665 pa_assert(result->length <= c.length);
666 c.length = result->length;
668 pa_memchunk_make_writable(&c, 0);
669 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
670 } else {
671 c = s->silence;
672 pa_memblock_ref(c.memblock);
673 pa_assert(result->length <= c.length);
674 c.length = result->length;
677 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
678 pa_source_output_assert_ref(o);
679 pa_assert(o->direct_on_input == i);
680 pa_source_post_direct(s->monitor_source, o, &c);
683 pa_memblock_unref(c.memblock);
687 if (m) {
688 if (m->chunk.memblock)
689 pa_memblock_unref(m->chunk.memblock);
690 pa_memchunk_reset(&m->chunk);
692 pa_sink_input_unref(m->userdata);
693 m->userdata = NULL;
695 n_unreffed += 1;
699 /* Now drop references to entries that are included in the
700 * pa_mix_info array but don't exist anymore */
702 if (n_unreffed < n) {
703 for (; n > 0; info++, n--) {
704 if (info->userdata)
705 pa_sink_input_unref(info->userdata);
706 if (info->chunk.memblock)
707 pa_memblock_unref(info->chunk.memblock);
711 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
712 pa_source_post(s->monitor_source, result);
715 /* Called from IO thread context */
716 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
717 pa_mix_info info[MAX_MIX_CHANNELS];
718 unsigned n;
719 size_t block_size_max;
721 pa_sink_assert_ref(s);
722 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
723 pa_assert(pa_frame_aligned(length, &s->sample_spec));
724 pa_assert(result);
726 pa_sink_ref(s);
728 pa_assert(!s->thread_info.rewind_requested);
729 pa_assert(s->thread_info.rewind_nbytes == 0);
731 if (s->thread_info.state == PA_SINK_SUSPENDED) {
732 result->memblock = pa_memblock_ref(s->silence.memblock);
733 result->index = s->silence.index;
734 result->length = PA_MIN(s->silence.length, length);
735 return;
738 if (length <= 0)
739 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
741 block_size_max = pa_mempool_block_size_max(s->core->mempool);
742 if (length > block_size_max)
743 length = pa_frame_align(block_size_max, &s->sample_spec);
745 pa_assert(length > 0);
747 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
749 if (n == 0) {
751 *result = s->silence;
752 pa_memblock_ref(result->memblock);
754 if (result->length > length)
755 result->length = length;
757 } else if (n == 1) {
758 pa_cvolume volume;
760 *result = info[0].chunk;
761 pa_memblock_ref(result->memblock);
763 if (result->length > length)
764 result->length = length;
766 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
768 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
769 pa_memchunk_make_writable(result, 0);
770 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
771 pa_silence_memchunk(result, &s->sample_spec);
772 else
773 pa_volume_memchunk(result, &s->sample_spec, &volume);
775 } else {
776 void *ptr;
777 result->memblock = pa_memblock_new(s->core->mempool, length);
779 ptr = pa_memblock_acquire(result->memblock);
780 result->length = pa_mix(info, n,
781 ptr, length,
782 &s->sample_spec,
783 &s->thread_info.soft_volume,
784 s->thread_info.soft_muted);
785 pa_memblock_release(result->memblock);
787 result->index = 0;
790 inputs_drop(s, info, n, result);
792 pa_sink_unref(s);
795 /* Called from IO thread context */
796 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
797 pa_mix_info info[MAX_MIX_CHANNELS];
798 unsigned n;
799 size_t length, block_size_max;
801 pa_sink_assert_ref(s);
802 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
803 pa_assert(target);
804 pa_assert(target->memblock);
805 pa_assert(target->length > 0);
806 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
808 pa_sink_ref(s);
810 pa_assert(!s->thread_info.rewind_requested);
811 pa_assert(s->thread_info.rewind_nbytes == 0);
813 if (s->thread_info.state == PA_SINK_SUSPENDED) {
814 pa_silence_memchunk(target, &s->sample_spec);
815 return;
818 length = target->length;
819 block_size_max = pa_mempool_block_size_max(s->core->mempool);
820 if (length > block_size_max)
821 length = pa_frame_align(block_size_max, &s->sample_spec);
823 pa_assert(length > 0);
825 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
827 if (n == 0) {
828 if (target->length > length)
829 target->length = length;
831 pa_silence_memchunk(target, &s->sample_spec);
832 } else if (n == 1) {
833 pa_cvolume volume;
835 if (target->length > length)
836 target->length = length;
838 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
840 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
841 pa_silence_memchunk(target, &s->sample_spec);
842 else {
843 pa_memchunk vchunk;
845 vchunk = info[0].chunk;
846 pa_memblock_ref(vchunk.memblock);
848 if (vchunk.length > length)
849 vchunk.length = length;
851 if (!pa_cvolume_is_norm(&volume)) {
852 pa_memchunk_make_writable(&vchunk, 0);
853 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
856 pa_memchunk_memcpy(target, &vchunk);
857 pa_memblock_unref(vchunk.memblock);
860 } else {
861 void *ptr;
863 ptr = pa_memblock_acquire(target->memblock);
865 target->length = pa_mix(info, n,
866 (uint8_t*) ptr + target->index, length,
867 &s->sample_spec,
868 &s->thread_info.soft_volume,
869 s->thread_info.soft_muted);
871 pa_memblock_release(target->memblock);
874 inputs_drop(s, info, n, target);
876 pa_sink_unref(s);
879 /* Called from IO thread context */
880 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
881 pa_memchunk chunk;
882 size_t l, d;
884 pa_sink_assert_ref(s);
885 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
886 pa_assert(target);
887 pa_assert(target->memblock);
888 pa_assert(target->length > 0);
889 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
891 pa_sink_ref(s);
893 pa_assert(!s->thread_info.rewind_requested);
894 pa_assert(s->thread_info.rewind_nbytes == 0);
896 l = target->length;
897 d = 0;
898 while (l > 0) {
899 chunk = *target;
900 chunk.index += d;
901 chunk.length -= d;
903 pa_sink_render_into(s, &chunk);
905 d += chunk.length;
906 l -= chunk.length;
909 pa_sink_unref(s);
912 /* Called from IO thread context */
913 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
914 pa_sink_assert_ref(s);
915 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
916 pa_assert(length > 0);
917 pa_assert(pa_frame_aligned(length, &s->sample_spec));
918 pa_assert(result);
920 pa_assert(!s->thread_info.rewind_requested);
921 pa_assert(s->thread_info.rewind_nbytes == 0);
923 /*** This needs optimization ***/
925 result->index = 0;
926 result->length = length;
927 result->memblock = pa_memblock_new(s->core->mempool, length);
929 pa_sink_render_into_full(s, result);
932 /* Called from main thread */
933 pa_usec_t pa_sink_get_latency(pa_sink *s) {
934 pa_usec_t usec = 0;
936 pa_sink_assert_ref(s);
937 pa_assert(PA_SINK_IS_LINKED(s->state));
939 /* The returned value is supposed to be in the time domain of the sound card! */
941 if (s->state == PA_SINK_SUSPENDED)
942 return 0;
944 if (!(s->flags & PA_SINK_LATENCY))
945 return 0;
947 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
949 return usec;
952 /* Called from main thread */
953 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
954 pa_sink_input *i;
955 uint32_t idx;
957 pa_sink_assert_ref(s);
958 pa_assert(new_volume);
959 pa_assert(PA_SINK_IS_LINKED(s->state));
960 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
962 /* This is called whenever a sink input volume changes and we
963 * might need to fix up the sink volume accordingly. Please note
964 * that we don't actually update the sinks volume here, we only
965 * return how it needs to be updated. The caller should then call
966 * pa_sink_set_flat_volume().*/
968 if (pa_idxset_isempty(s->inputs)) {
969 /* In the special case that we have no sink input we leave the
970 * volume unmodified. */
971 *new_volume = s->virtual_volume;
972 return;
975 pa_cvolume_mute(new_volume, s->channel_map.channels);
977 /* First let's determine the new maximum volume of all inputs
978 * connected to this sink */
979 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
980 unsigned c;
981 pa_cvolume remapped_volume;
983 remapped_volume = i->virtual_volume;
984 pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
986 for (c = 0; c < new_volume->channels; c++)
987 if (remapped_volume.values[c] > new_volume->values[c])
988 new_volume->values[c] = remapped_volume.values[c];
991 /* Then, let's update the soft volumes of all inputs connected
992 * to this sink */
993 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
994 pa_cvolume remapped_new_volume;
996 remapped_new_volume = *new_volume;
997 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
998 pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
999 pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor);
1001 /* Hooks have the ability to play games with i->soft_volume */
1002 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1004 /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
1005 * we want the update to have atomically with the sink
1006 * volume update, hence we do it within the
1007 * pa_sink_set_flat_volume() call below*/
1011 /* Called from main thread */
1012 void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
1013 pa_sink_input *i;
1014 uint32_t idx;
1016 pa_sink_assert_ref(s);
1017 pa_assert(old_volume);
1018 pa_assert(PA_SINK_IS_LINKED(s->state));
1019 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1021 /* This is called whenever the sink volume changes that is not
1022 * caused by a sink input volume change. We need to fix up the
1023 * sink input volumes accordingly */
1025 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1026 pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
1027 unsigned c;
1029 remapped_new_volume = s->virtual_volume;
1030 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1032 remapped_old_volume = *old_volume;
1033 pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
1035 for (c = 0; c < i->sample_spec.channels; c++)
1037 if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
1038 fixed_volume.values[c] = PA_VOLUME_MUTED;
1039 else
1040 fixed_volume.values[c] = (pa_volume_t)
1041 ((uint64_t) i->virtual_volume.values[c] *
1042 (uint64_t) remapped_new_volume.values[c] /
1043 (uint64_t) remapped_old_volume.values[c]);
1045 fixed_volume.channels = i->virtual_volume.channels;
1047 if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
1048 i->virtual_volume = fixed_volume;
1050 /* The virtual volume changed, let's tell people so */
1051 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1056 /* Called from main thread */
1057 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1058 pa_cvolume old_virtual_volume;
1059 pa_bool_t virtual_volume_changed;
1061 pa_sink_assert_ref(s);
1062 pa_assert(PA_SINK_IS_LINKED(s->state));
1063 pa_assert(volume);
1064 pa_assert(pa_cvolume_valid(volume));
1065 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1067 old_virtual_volume = s->virtual_volume;
1068 s->virtual_volume = *volume;
1069 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
1071 /* Propagate this volume change back to the inputs */
1072 if (virtual_volume_changed)
1073 if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1074 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1076 if (s->set_volume) {
1077 /* If we have a function set_volume(), then we do not apply a
1078 * soft volume by default. However, set_volume() is apply one
1079 * to s->soft_volume */
1081 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1082 s->set_volume(s);
1084 } else
1085 /* If we have no function set_volume(), then the soft volume
1086 * becomes the virtual volume */
1087 s->soft_volume = s->virtual_volume;
1089 /* This tells the sink that soft and/or virtual volume changed */
1090 if (sendmsg)
1091 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1093 if (virtual_volume_changed)
1094 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1097 /* Called from main thread. Only to be called by sink implementor */
1098 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1099 pa_sink_assert_ref(s);
1100 pa_assert(volume);
1102 s->soft_volume = *volume;
1104 if (PA_SINK_IS_LINKED(s->state))
1105 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1106 else
1107 s->thread_info.soft_volume = *volume;
1110 /* Called from main thread */
1111 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1112 pa_sink_assert_ref(s);
1114 if (s->refresh_volume || force_refresh) {
1115 struct pa_cvolume old_virtual_volume = s->virtual_volume;
1117 if (s->get_volume)
1118 s->get_volume(s);
1120 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1122 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1124 if (s->flags & PA_SINK_FLAT_VOLUME)
1125 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1127 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1131 return &s->virtual_volume;
1134 /* Called from main thread */
1135 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1136 pa_bool_t old_muted;
1138 pa_sink_assert_ref(s);
1139 pa_assert(PA_SINK_IS_LINKED(s->state));
1141 old_muted = s->muted;
1142 s->muted = mute;
1144 if (s->set_mute)
1145 s->set_mute(s);
1147 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1149 if (old_muted != s->muted)
1150 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1153 /* Called from main thread */
1154 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1156 pa_sink_assert_ref(s);
1158 if (s->refresh_muted || force_refresh) {
1159 pa_bool_t old_muted = s->muted;
1161 if (s->get_mute)
1162 s->get_mute(s);
1164 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1166 if (old_muted != s->muted)
1167 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1170 return s->muted;
1173 /* Called from main thread */
1174 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1176 pa_sink_assert_ref(s);
1177 pa_assert(p);
1179 pa_proplist_update(s->proplist, mode, p);
1181 if (PA_SINK_IS_LINKED(s->state)) {
1182 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1183 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1186 return TRUE;
1189 /* Called from main thread */
1190 void pa_sink_set_description(pa_sink *s, const char *description) {
1191 const char *old;
1192 pa_sink_assert_ref(s);
1194 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1195 return;
1197 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1199 if (old && description && !strcmp(old, description))
1200 return;
1202 if (description)
1203 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1204 else
1205 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1207 if (s->monitor_source) {
1208 char *n;
1210 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1211 pa_source_set_description(s->monitor_source, n);
1212 pa_xfree(n);
1215 if (PA_SINK_IS_LINKED(s->state)) {
1216 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1217 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1221 /* Called from main thread */
1222 unsigned pa_sink_linked_by(pa_sink *s) {
1223 unsigned ret;
1225 pa_sink_assert_ref(s);
1226 pa_assert(PA_SINK_IS_LINKED(s->state));
1228 ret = pa_idxset_size(s->inputs);
1230 /* We add in the number of streams connected to us here. Please
1231 * note the asymmmetry to pa_sink_used_by()! */
1233 if (s->monitor_source)
1234 ret += pa_source_linked_by(s->monitor_source);
1236 return ret;
1239 /* Called from main thread */
1240 unsigned pa_sink_used_by(pa_sink *s) {
1241 unsigned ret;
1243 pa_sink_assert_ref(s);
1244 pa_assert(PA_SINK_IS_LINKED(s->state));
1246 ret = pa_idxset_size(s->inputs);
1247 pa_assert(ret >= s->n_corked);
1249 /* Streams connected to our monitor source do not matter for
1250 * pa_sink_used_by()!.*/
1252 return ret - s->n_corked;
1255 /* Called from main thread */
1256 unsigned pa_sink_check_suspend(pa_sink *s) {
1257 unsigned ret;
1258 pa_sink_input *i;
1259 uint32_t idx;
1261 pa_sink_assert_ref(s);
1263 if (!PA_SINK_IS_LINKED(s->state))
1264 return 0;
1266 ret = 0;
1268 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1269 pa_sink_input_state_t st;
1271 st = pa_sink_input_get_state(i);
1272 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1274 if (st == PA_SINK_INPUT_CORKED)
1275 continue;
1277 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1278 continue;
1280 ret ++;
1283 if (s->monitor_source)
1284 ret += pa_source_check_suspend(s->monitor_source);
1286 return ret;
1289 /* Called from the IO thread */
1290 static void sync_input_volumes_within_thread(pa_sink *s) {
1291 pa_sink_input *i;
1292 void *state = NULL;
1294 pa_sink_assert_ref(s);
1296 while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1297 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1298 continue;
1300 i->thread_info.soft_volume = i->soft_volume;
1301 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1305 /* Called from IO thread, except when it is not */
1306 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1307 pa_sink *s = PA_SINK(o);
1308 pa_sink_assert_ref(s);
1310 switch ((pa_sink_message_t) code) {
1312 case PA_SINK_MESSAGE_ADD_INPUT: {
1313 pa_sink_input *i = PA_SINK_INPUT(userdata);
1315 /* If you change anything here, make sure to change the
1316 * sink input handling a few lines down at
1317 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1319 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1321 /* Since the caller sleeps in pa_sink_input_put(), we can
1322 * safely access data outside of thread_info even though
1323 * it is mutable */
1325 if ((i->thread_info.sync_prev = i->sync_prev)) {
1326 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1327 pa_assert(i->sync_prev->sync_next == i);
1328 i->thread_info.sync_prev->thread_info.sync_next = i;
1331 if ((i->thread_info.sync_next = i->sync_next)) {
1332 pa_assert(i->sink == i->thread_info.sync_next->sink);
1333 pa_assert(i->sync_next->sync_prev == i);
1334 i->thread_info.sync_next->thread_info.sync_prev = i;
1337 pa_assert(!i->thread_info.attached);
1338 i->thread_info.attached = TRUE;
1340 if (i->attach)
1341 i->attach(i);
1343 pa_sink_input_set_state_within_thread(i, i->state);
1345 /* The requested latency of the sink input needs to be
1346 * fixed up and then configured on the sink */
1348 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1349 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1351 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1352 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1354 /* We don't rewind here automatically. This is left to the
1355 * sink input implementor because some sink inputs need a
1356 * slow start, i.e. need some time to buffer client
1357 * samples before beginning streaming. */
1359 /* In flat volume mode we need to update the volume as
1360 * well */
1361 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1364 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1365 pa_sink_input *i = PA_SINK_INPUT(userdata);
1367 /* If you change anything here, make sure to change the
1368 * sink input handling a few lines down at
1369 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1371 if (i->detach)
1372 i->detach(i);
1374 pa_sink_input_set_state_within_thread(i, i->state);
1376 pa_assert(i->thread_info.attached);
1377 i->thread_info.attached = FALSE;
1379 /* Since the caller sleeps in pa_sink_input_unlink(),
1380 * we can safely access data outside of thread_info even
1381 * though it is mutable */
1383 pa_assert(!i->sync_prev);
1384 pa_assert(!i->sync_next);
1386 if (i->thread_info.sync_prev) {
1387 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1388 i->thread_info.sync_prev = NULL;
1391 if (i->thread_info.sync_next) {
1392 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1393 i->thread_info.sync_next = NULL;
1396 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1397 pa_sink_input_unref(i);
1399 pa_sink_invalidate_requested_latency(s);
1400 pa_sink_request_rewind(s, (size_t) -1);
1402 /* In flat volume mode we need to update the volume as
1403 * well */
1404 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1407 case PA_SINK_MESSAGE_START_MOVE: {
1408 pa_sink_input *i = PA_SINK_INPUT(userdata);
1410 /* We don't support moving synchronized streams. */
1411 pa_assert(!i->sync_prev);
1412 pa_assert(!i->sync_next);
1413 pa_assert(!i->thread_info.sync_next);
1414 pa_assert(!i->thread_info.sync_prev);
1416 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1417 pa_usec_t usec = 0;
1418 size_t sink_nbytes, total_nbytes;
1420 /* Get the latency of the sink */
1421 if (!(s->flags & PA_SINK_LATENCY) ||
1422 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1423 usec = 0;
1425 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1426 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1428 if (total_nbytes > 0) {
1429 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1430 i->thread_info.rewrite_flush = TRUE;
1431 pa_sink_input_process_rewind(i, sink_nbytes);
1435 if (i->detach)
1436 i->detach(i);
1438 pa_assert(i->thread_info.attached);
1439 i->thread_info.attached = FALSE;
1441 /* Let's remove the sink input ...*/
1442 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1443 pa_sink_input_unref(i);
1445 pa_sink_invalidate_requested_latency(s);
1447 pa_log_debug("Requesting rewind due to started move");
1448 pa_sink_request_rewind(s, (size_t) -1);
1450 /* In flat volume mode we need to update the volume as
1451 * well */
1452 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1455 case PA_SINK_MESSAGE_FINISH_MOVE: {
1456 pa_sink_input *i = PA_SINK_INPUT(userdata);
1458 /* We don't support moving synchronized streams. */
1459 pa_assert(!i->sync_prev);
1460 pa_assert(!i->sync_next);
1461 pa_assert(!i->thread_info.sync_next);
1462 pa_assert(!i->thread_info.sync_prev);
1464 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1466 pa_assert(!i->thread_info.attached);
1467 i->thread_info.attached = TRUE;
1469 if (i->attach)
1470 i->attach(i);
1472 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1473 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1475 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1476 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1478 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1479 pa_usec_t usec = 0;
1480 size_t nbytes;
1482 /* Get the latency of the sink */
1483 if (!(s->flags & PA_SINK_LATENCY) ||
1484 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1485 usec = 0;
1487 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1489 if (nbytes > 0)
1490 pa_sink_input_drop(i, nbytes);
1492 pa_log_debug("Requesting rewind due to finished move");
1493 pa_sink_request_rewind(s, nbytes);
1496 /* In flat volume mode we need to update the volume as
1497 * well */
1498 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1501 case PA_SINK_MESSAGE_SET_VOLUME:
1503 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1504 s->thread_info.soft_volume = s->soft_volume;
1505 pa_sink_request_rewind(s, (size_t) -1);
1508 if (s->flags & PA_SINK_FLAT_VOLUME)
1509 sync_input_volumes_within_thread(s);
1511 return 0;
1513 case PA_SINK_MESSAGE_GET_VOLUME:
1514 return 0;
1516 case PA_SINK_MESSAGE_SET_MUTE:
1518 if (s->thread_info.soft_muted != s->muted) {
1519 s->thread_info.soft_muted = s->muted;
1520 pa_sink_request_rewind(s, (size_t) -1);
1523 return 0;
1525 case PA_SINK_MESSAGE_GET_MUTE:
1526 return 0;
1528 case PA_SINK_MESSAGE_SET_STATE:
1530 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1532 if (s->thread_info.state == PA_SINK_SUSPENDED)
1533 s->thread_info.rewind_requested = FALSE;
1535 return 0;
1537 case PA_SINK_MESSAGE_DETACH:
1539 /* Detach all streams */
1540 pa_sink_detach_within_thread(s);
1541 return 0;
1543 case PA_SINK_MESSAGE_ATTACH:
1545 /* Reattach all streams */
1546 pa_sink_attach_within_thread(s);
1547 return 0;
1549 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1551 pa_usec_t *usec = userdata;
1552 *usec = pa_sink_get_requested_latency_within_thread(s);
1554 if (*usec == (pa_usec_t) -1)
1555 *usec = s->thread_info.max_latency;
1557 return 0;
1560 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1561 pa_usec_t *r = userdata;
1563 pa_sink_update_latency_range(s, r[0], r[1]);
1565 return 0;
1568 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1569 pa_usec_t *r = userdata;
1571 r[0] = s->thread_info.min_latency;
1572 r[1] = s->thread_info.max_latency;
1574 return 0;
1577 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1579 *((size_t*) userdata) = s->thread_info.max_rewind;
1580 return 0;
1582 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1584 *((size_t*) userdata) = s->thread_info.max_request;
1585 return 0;
1587 case PA_SINK_MESSAGE_GET_LATENCY:
1588 case PA_SINK_MESSAGE_MAX:
1592 return -1;
1595 /* Called from main thread */
1596 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1597 pa_sink *sink;
1598 uint32_t idx;
1599 int ret = 0;
1601 pa_core_assert_ref(c);
1603 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx)))
1604 ret -= pa_sink_suspend(sink, suspend) < 0;
1606 return ret;
1609 /* Called from main thread */
1610 void pa_sink_detach(pa_sink *s) {
1611 pa_sink_assert_ref(s);
1612 pa_assert(PA_SINK_IS_LINKED(s->state));
1614 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1617 /* Called from main thread */
1618 void pa_sink_attach(pa_sink *s) {
1619 pa_sink_assert_ref(s);
1620 pa_assert(PA_SINK_IS_LINKED(s->state));
1622 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1625 /* Called from IO thread */
1626 void pa_sink_detach_within_thread(pa_sink *s) {
1627 pa_sink_input *i;
1628 void *state = NULL;
1630 pa_sink_assert_ref(s);
1631 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1633 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1634 if (i->detach)
1635 i->detach(i);
1637 if (s->monitor_source)
1638 pa_source_detach_within_thread(s->monitor_source);
1641 /* Called from IO thread */
1642 void pa_sink_attach_within_thread(pa_sink *s) {
1643 pa_sink_input *i;
1644 void *state = NULL;
1646 pa_sink_assert_ref(s);
1647 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1649 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1650 if (i->attach)
1651 i->attach(i);
1653 if (s->monitor_source)
1654 pa_source_attach_within_thread(s->monitor_source);
1657 /* Called from IO thread */
1658 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1659 pa_sink_assert_ref(s);
1660 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1662 if (s->thread_info.state == PA_SINK_SUSPENDED)
1663 return;
1665 if (nbytes == (size_t) -1)
1666 nbytes = s->thread_info.max_rewind;
1668 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1670 if (s->thread_info.rewind_requested &&
1671 nbytes <= s->thread_info.rewind_nbytes)
1672 return;
1674 s->thread_info.rewind_nbytes = nbytes;
1675 s->thread_info.rewind_requested = TRUE;
1677 if (s->request_rewind)
1678 s->request_rewind(s);
1681 /* Called from IO thread */
1682 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1683 pa_usec_t result = (pa_usec_t) -1;
1684 pa_sink_input *i;
1685 void *state = NULL;
1686 pa_usec_t monitor_latency;
1688 pa_sink_assert_ref(s);
1690 if (s->thread_info.requested_latency_valid)
1691 return s->thread_info.requested_latency;
1693 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1695 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1696 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1697 result = i->thread_info.requested_sink_latency;
1699 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1701 if (monitor_latency != (pa_usec_t) -1 &&
1702 (result == (pa_usec_t) -1 || result > monitor_latency))
1703 result = monitor_latency;
1705 if (result != (pa_usec_t) -1) {
1706 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1707 result = s->thread_info.max_latency;
1709 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1710 result = s->thread_info.min_latency;
1713 s->thread_info.requested_latency = result;
1714 s->thread_info.requested_latency_valid = TRUE;
1716 return result;
1719 /* Called from main thread */
1720 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1721 pa_usec_t usec = 0;
1723 pa_sink_assert_ref(s);
1724 pa_assert(PA_SINK_IS_LINKED(s->state));
1726 if (s->state == PA_SINK_SUSPENDED)
1727 return 0;
1729 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1730 return usec;
1733 /* Called from IO thread */
1734 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1735 pa_sink_input *i;
1736 void *state = NULL;
1738 pa_sink_assert_ref(s);
1740 if (max_rewind == s->thread_info.max_rewind)
1741 return;
1743 s->thread_info.max_rewind = max_rewind;
1745 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1746 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1747 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1750 if (s->monitor_source)
1751 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
1754 /* Called from IO thread */
1755 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1756 void *state = NULL;
1758 pa_sink_assert_ref(s);
1760 if (max_request == s->thread_info.max_request)
1761 return;
1763 s->thread_info.max_request = max_request;
1765 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1766 pa_sink_input *i;
1768 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1769 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1773 /* Called from IO thread */
1774 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1775 pa_sink_input *i;
1776 void *state = NULL;
1778 pa_sink_assert_ref(s);
1780 s->thread_info.requested_latency_valid = FALSE;
1782 if (s->update_requested_latency)
1783 s->update_requested_latency(s);
1785 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1786 if (i->update_sink_requested_latency)
1787 i->update_sink_requested_latency(i);
1790 /* Called from main thread */
1791 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1792 pa_sink_assert_ref(s);
1794 /* min_latency == 0: no limit
1795 * min_latency == (size_t) -1: default limit
1796 * min_latency anything else: specified limit
1798 * Similar for max_latency */
1800 if (min_latency == (pa_usec_t) -1)
1801 min_latency = DEFAULT_MIN_LATENCY;
1803 if (max_latency == (pa_usec_t) -1)
1804 max_latency = min_latency;
1806 pa_assert(!min_latency || !max_latency ||
1807 min_latency <= max_latency);
1809 if (PA_SINK_IS_LINKED(s->state)) {
1810 pa_usec_t r[2];
1812 r[0] = min_latency;
1813 r[1] = max_latency;
1815 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1816 } else {
1817 s->thread_info.min_latency = min_latency;
1818 s->thread_info.max_latency = max_latency;
1820 s->monitor_source->thread_info.min_latency = min_latency;
1821 s->monitor_source->thread_info.max_latency = max_latency;
1823 s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
1827 /* Called from main thread */
1828 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1829 pa_sink_assert_ref(s);
1830 pa_assert(min_latency);
1831 pa_assert(max_latency);
1833 if (PA_SINK_IS_LINKED(s->state)) {
1834 pa_usec_t r[2] = { 0, 0 };
1836 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1838 *min_latency = r[0];
1839 *max_latency = r[1];
1840 } else {
1841 *min_latency = s->thread_info.min_latency;
1842 *max_latency = s->thread_info.max_latency;
1846 /* Called from IO thread */
1847 void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1848 pa_sink_input *i;
1849 void *state = NULL;
1851 pa_sink_assert_ref(s);
1853 pa_assert(!min_latency || !max_latency ||
1854 min_latency <= max_latency);
1856 s->thread_info.min_latency = min_latency;
1857 s->thread_info.max_latency = max_latency;
1859 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1860 if (i->update_sink_latency_range)
1861 i->update_sink_latency_range(i);
1863 pa_sink_invalidate_requested_latency(s);
1865 pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
1868 /* Called from main context */
1869 size_t pa_sink_get_max_rewind(pa_sink *s) {
1870 size_t r;
1871 pa_sink_assert_ref(s);
1873 if (!PA_SINK_IS_LINKED(s->state))
1874 return s->thread_info.max_rewind;
1876 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1878 return r;
1881 /* Called from main context */
1882 size_t pa_sink_get_max_request(pa_sink *s) {
1883 size_t r;
1884 pa_sink_assert_ref(s);
1886 if (!PA_SINK_IS_LINKED(s->state))
1887 return s->thread_info.max_request;
1889 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1891 return r;
1894 /* Called from main context */
1895 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
1896 const char *ff, *t = NULL, *s = "", *profile, *bus;
1898 pa_assert(p);
1900 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
1901 return TRUE;
1903 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
1905 if (pa_streq(ff, "microphone"))
1906 t = "audio-input-microphone";
1907 else if (pa_streq(ff, "webcam"))
1908 t = "camera-web";
1909 else if (pa_streq(ff, "computer"))
1910 t = "computer";
1911 else if (pa_streq(ff, "handset"))
1912 t = "phone";
1915 if (!t) {
1916 if (is_sink)
1917 t = "audio-card";
1918 else
1919 t = "audio-input-microphone";
1922 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
1923 if (strstr(profile, "analog"))
1924 s = "-analog";
1925 else if (strstr(profile, "iec958"))
1926 s = "-iec958";
1927 else if (strstr(profile, "hdmi"))
1928 s = "-hdmi";
1931 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
1933 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
1935 return TRUE;
1938 pa_bool_t pa_device_init_description(pa_proplist *p) {
1939 const char *s;
1940 pa_assert(p);
1942 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
1943 return TRUE;
1945 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
1946 if (pa_streq(s, "internal")) {
1947 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
1948 return TRUE;
1951 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
1952 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
1953 return TRUE;
1956 return FALSE;