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
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>
49 #define MAX_MIX_CHANNELS 32
50 #define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
51 #define ABSOLUTE_MIN_LATENCY (500)
52 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
53 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
55 static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
57 static void sink_free(pa_object *s);
59 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
62 memset(data, 0, sizeof(*data));
63 data->proplist = pa_proplist_new();
68 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
72 data->name = pa_xstrdup(name);
75 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
78 if ((data->sample_spec_is_set = !!spec))
79 data->sample_spec = *spec;
82 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
85 if ((data->channel_map_is_set = !!map))
86 data->channel_map = *map;
89 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
92 if ((data->volume_is_set = !!volume))
93 data->volume = *volume;
96 void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
99 data->muted_is_set = TRUE;
100 data->muted = !!mute;
103 void pa_sink_new_data_done(pa_sink_new_data *data) {
106 pa_xfree(data->name);
107 pa_proplist_free(data->proplist);
110 /* Called from main context */
111 static void reset_callbacks(pa_sink *s) {
115 s->get_volume = NULL;
116 s->set_volume = NULL;
119 s->request_rewind = NULL;
120 s->update_requested_latency = NULL;
123 /* Called from main context */
124 pa_sink* pa_sink_new(
126 pa_sink_new_data *data,
127 pa_sink_flags_t flags) {
131 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
132 pa_source_new_data source_data;
138 pa_assert(data->name);
140 s = pa_msgobject_new(pa_sink);
142 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
147 pa_sink_new_data_set_name(data, name);
149 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
151 pa_namereg_unregister(core, name);
155 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
156 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
158 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
160 if (!data->channel_map_is_set)
161 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
163 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
164 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
166 if (!data->volume_is_set)
167 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
169 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
170 pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels);
172 if (!data->muted_is_set)
176 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
178 pa_device_init_description(data->proplist);
179 pa_device_init_icon(data->proplist, TRUE);
181 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
183 pa_namereg_unregister(core, name);
187 s->parent.parent.free = sink_free;
188 s->parent.process_msg = pa_sink_process_msg;
191 s->state = PA_SINK_INIT;
193 s->name = pa_xstrdup(name);
194 s->proplist = pa_proplist_copy(data->proplist);
195 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
196 s->module = data->module;
197 s->card = data->card;
199 s->sample_spec = data->sample_spec;
200 s->channel_map = data->channel_map;
202 s->inputs = pa_idxset_new(NULL, NULL);
205 s->reference_volume = s->virtual_volume = data->volume;
206 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
207 s->base_volume = PA_VOLUME_NORM;
208 s->n_volume_steps = PA_VOLUME_NORM+1;
209 s->muted = data->muted;
210 s->refresh_volume = s->refresh_muted = FALSE;
212 s->fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
220 pa_silence_memchunk_get(
221 &core->silence_cache,
227 s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
228 s->thread_info.soft_volume = s->soft_volume;
229 s->thread_info.soft_muted = s->muted;
230 s->thread_info.state = s->state;
231 s->thread_info.rewind_nbytes = 0;
232 s->thread_info.rewind_requested = FALSE;
233 s->thread_info.max_rewind = 0;
234 s->thread_info.max_request = 0;
235 s->thread_info.requested_latency_valid = FALSE;
236 s->thread_info.requested_latency = 0;
237 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
238 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
240 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
243 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
245 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
246 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
249 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
250 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
254 pa_source_new_data_init(&source_data);
255 pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
256 pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
257 source_data.name = pa_sprintf_malloc("%s.monitor", name);
258 source_data.driver = data->driver;
259 source_data.module = data->module;
260 source_data.card = data->card;
262 dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
263 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
264 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
266 s->monitor_source = pa_source_new(core, &source_data,
267 ((flags & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
268 ((flags & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0));
270 pa_source_new_data_done(&source_data);
272 if (!s->monitor_source) {
278 s->monitor_source->monitor_of = s;
280 pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
281 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
286 /* Called from main context */
287 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
289 pa_bool_t suspend_change;
290 pa_sink_state_t original_state;
294 if (s->state == state)
297 original_state = s->state;
300 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
301 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
304 if ((ret = s->set_state(s, state)) < 0)
308 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
311 s->set_state(s, original_state);
318 if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
319 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
320 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
323 if (suspend_change) {
327 /* We're suspending or resuming, tell everyone about it */
329 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
330 if (s->state == PA_SINK_SUSPENDED &&
331 (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
332 pa_sink_input_kill(i);
334 i->suspend(i, state == PA_SINK_SUSPENDED);
336 if (s->monitor_source)
337 pa_source_sync_suspend(s->monitor_source);
343 /* Called from main context */
344 void pa_sink_put(pa_sink* s) {
345 pa_sink_assert_ref(s);
347 pa_assert(s->state == PA_SINK_INIT);
349 /* The following fields must be initialized properly when calling _put() */
350 pa_assert(s->asyncmsgq);
351 pa_assert(s->rtpoll);
352 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
354 /* Generally, flags should be initialized via pa_sink_new(). As a
355 * special exception we allow volume related flags to be set
356 * between _new() and _put(). */
358 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL))
359 s->flags |= PA_SINK_DECIBEL_VOLUME;
361 if ((s->flags & PA_SINK_DECIBEL_VOLUME) && s->core->flat_volumes)
362 s->flags |= PA_SINK_FLAT_VOLUME;
364 s->thread_info.soft_volume = s->soft_volume;
365 s->thread_info.soft_muted = s->muted;
367 pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL) || (s->base_volume == PA_VOLUME_NORM && s->flags & PA_SINK_DECIBEL_VOLUME));
368 pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
369 pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == (s->fixed_latency != 0));
370 pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
371 pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY));
373 pa_assert(s->monitor_source->fixed_latency == s->fixed_latency);
374 pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency);
375 pa_assert(s->monitor_source->thread_info.max_latency == s->thread_info.max_latency);
377 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
379 pa_source_put(s->monitor_source);
381 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
382 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
385 /* Called from main context */
386 void pa_sink_unlink(pa_sink* s) {
388 pa_sink_input *i, *j = NULL;
392 /* Please note that pa_sink_unlink() does more than simply
393 * reversing pa_sink_put(). It also undoes the registrations
394 * already done in pa_sink_new()! */
396 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
397 * may be called multiple times on the same sink without bad
400 linked = PA_SINK_IS_LINKED(s->state);
403 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
405 if (s->state != PA_SINK_UNLINKED)
406 pa_namereg_unregister(s->core, s->name);
407 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
410 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
412 while ((i = pa_idxset_first(s->inputs, NULL))) {
414 pa_sink_input_kill(i);
419 sink_set_state(s, PA_SINK_UNLINKED);
421 s->state = PA_SINK_UNLINKED;
425 if (s->monitor_source)
426 pa_source_unlink(s->monitor_source);
429 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
430 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
434 /* Called from main context */
435 static void sink_free(pa_object *o) {
436 pa_sink *s = PA_SINK(o);
440 pa_assert(pa_sink_refcnt(s) == 0);
442 if (PA_SINK_IS_LINKED(s->state))
445 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
447 if (s->monitor_source) {
448 pa_source_unref(s->monitor_source);
449 s->monitor_source = NULL;
452 pa_idxset_free(s->inputs, NULL, NULL);
454 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
455 pa_sink_input_unref(i);
457 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
459 if (s->silence.memblock)
460 pa_memblock_unref(s->silence.memblock);
466 pa_proplist_free(s->proplist);
471 /* Called from main context */
472 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
473 pa_sink_assert_ref(s);
477 if (s->monitor_source)
478 pa_source_set_asyncmsgq(s->monitor_source, q);
481 /* Called from main context */
482 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
483 pa_sink_assert_ref(s);
486 if (s->monitor_source)
487 pa_source_set_rtpoll(s->monitor_source, p);
490 /* Called from main context */
491 int pa_sink_update_status(pa_sink*s) {
492 pa_sink_assert_ref(s);
493 pa_assert(PA_SINK_IS_LINKED(s->state));
495 if (s->state == PA_SINK_SUSPENDED)
498 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
501 /* Called from main context */
502 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
503 pa_sink_assert_ref(s);
504 pa_assert(PA_SINK_IS_LINKED(s->state));
507 return sink_set_state(s, PA_SINK_SUSPENDED);
509 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
512 /* Called from main context */
513 pa_queue *pa_sink_move_all_start(pa_sink *s) {
515 pa_sink_input *i, *n;
518 pa_sink_assert_ref(s);
519 pa_assert(PA_SINK_IS_LINKED(s->state));
523 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
524 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
526 pa_sink_input_ref(i);
528 if (pa_sink_input_start_move(i) >= 0)
531 pa_sink_input_unref(i);
537 /* Called from main context */
538 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
541 pa_sink_assert_ref(s);
542 pa_assert(PA_SINK_IS_LINKED(s->state));
545 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
546 if (pa_sink_input_finish_move(i, s, save) < 0)
547 pa_sink_input_kill(i);
549 pa_sink_input_unref(i);
552 pa_queue_free(q, NULL, NULL);
555 /* Called from main context */
556 void pa_sink_move_all_fail(pa_queue *q) {
560 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
561 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
562 pa_sink_input_kill(i);
563 pa_sink_input_unref(i);
567 pa_queue_free(q, NULL, NULL);
570 /* Called from IO thread context */
571 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
574 pa_sink_assert_ref(s);
575 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
577 /* If nobody requested this and this is actually no real rewind
578 * then we can short cut this */
579 if (!s->thread_info.rewind_requested && nbytes <= 0)
582 s->thread_info.rewind_nbytes = 0;
583 s->thread_info.rewind_requested = FALSE;
585 if (s->thread_info.state == PA_SINK_SUSPENDED)
589 pa_log_debug("Processing rewind...");
591 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
592 pa_sink_input_assert_ref(i);
593 pa_sink_input_process_rewind(i, nbytes);
597 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
598 pa_source_process_rewind(s->monitor_source, nbytes);
601 /* Called from IO thread context */
602 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
606 size_t mixlength = *length;
608 pa_sink_assert_ref(s);
611 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
612 pa_sink_input_assert_ref(i);
614 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
616 if (mixlength == 0 || info->chunk.length < mixlength)
617 mixlength = info->chunk.length;
619 if (pa_memblock_is_silence(info->chunk.memblock)) {
620 pa_memblock_unref(info->chunk.memblock);
624 info->userdata = pa_sink_input_ref(i);
626 pa_assert(info->chunk.memblock);
627 pa_assert(info->chunk.length > 0);
640 /* Called from IO thread context */
641 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
645 unsigned n_unreffed = 0;
647 pa_sink_assert_ref(s);
649 pa_assert(result->memblock);
650 pa_assert(result->length > 0);
652 /* We optimize for the case where the order of the inputs has not changed */
654 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
656 pa_mix_info* m = NULL;
658 pa_sink_input_assert_ref(i);
660 /* Let's try to find the matching entry info the pa_mix_info array */
661 for (j = 0; j < n; j ++) {
663 if (info[p].userdata == i) {
674 pa_sink_input_drop(i, result->length);
676 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
678 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
683 if (m && m->chunk.memblock) {
685 pa_memblock_ref(c.memblock);
686 pa_assert(result->length <= c.length);
687 c.length = result->length;
689 pa_memchunk_make_writable(&c, 0);
690 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
693 pa_memblock_ref(c.memblock);
694 pa_assert(result->length <= c.length);
695 c.length = result->length;
698 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
699 pa_source_output_assert_ref(o);
700 pa_assert(o->direct_on_input == i);
701 pa_source_post_direct(s->monitor_source, o, &c);
704 pa_memblock_unref(c.memblock);
709 if (m->chunk.memblock)
710 pa_memblock_unref(m->chunk.memblock);
711 pa_memchunk_reset(&m->chunk);
713 pa_sink_input_unref(m->userdata);
720 /* Now drop references to entries that are included in the
721 * pa_mix_info array but don't exist anymore */
723 if (n_unreffed < n) {
724 for (; n > 0; info++, n--) {
726 pa_sink_input_unref(info->userdata);
727 if (info->chunk.memblock)
728 pa_memblock_unref(info->chunk.memblock);
732 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
733 pa_source_post(s->monitor_source, result);
736 /* Called from IO thread context */
737 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
738 pa_mix_info info[MAX_MIX_CHANNELS];
740 size_t block_size_max;
742 pa_sink_assert_ref(s);
743 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
744 pa_assert(pa_frame_aligned(length, &s->sample_spec));
749 pa_assert(!s->thread_info.rewind_requested);
750 pa_assert(s->thread_info.rewind_nbytes == 0);
752 if (s->thread_info.state == PA_SINK_SUSPENDED) {
753 result->memblock = pa_memblock_ref(s->silence.memblock);
754 result->index = s->silence.index;
755 result->length = PA_MIN(s->silence.length, length);
760 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
762 block_size_max = pa_mempool_block_size_max(s->core->mempool);
763 if (length > block_size_max)
764 length = pa_frame_align(block_size_max, &s->sample_spec);
766 pa_assert(length > 0);
768 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
772 *result = s->silence;
773 pa_memblock_ref(result->memblock);
775 if (result->length > length)
776 result->length = length;
781 *result = info[0].chunk;
782 pa_memblock_ref(result->memblock);
784 if (result->length > length)
785 result->length = length;
787 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
789 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
790 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
791 pa_memblock_unref(result->memblock);
792 pa_silence_memchunk_get(&s->core->silence_cache,
798 pa_memchunk_make_writable(result, 0);
799 pa_volume_memchunk(result, &s->sample_spec, &volume);
804 result->memblock = pa_memblock_new(s->core->mempool, length);
806 ptr = pa_memblock_acquire(result->memblock);
807 result->length = pa_mix(info, n,
810 &s->thread_info.soft_volume,
811 s->thread_info.soft_muted);
812 pa_memblock_release(result->memblock);
817 inputs_drop(s, info, n, result);
822 /* Called from IO thread context */
823 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
824 pa_mix_info info[MAX_MIX_CHANNELS];
826 size_t length, block_size_max;
828 pa_sink_assert_ref(s);
829 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
831 pa_assert(target->memblock);
832 pa_assert(target->length > 0);
833 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
837 pa_assert(!s->thread_info.rewind_requested);
838 pa_assert(s->thread_info.rewind_nbytes == 0);
840 if (s->thread_info.state == PA_SINK_SUSPENDED) {
841 pa_silence_memchunk(target, &s->sample_spec);
845 length = target->length;
846 block_size_max = pa_mempool_block_size_max(s->core->mempool);
847 if (length > block_size_max)
848 length = pa_frame_align(block_size_max, &s->sample_spec);
850 pa_assert(length > 0);
852 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
855 if (target->length > length)
856 target->length = length;
858 pa_silence_memchunk(target, &s->sample_spec);
862 if (target->length > length)
863 target->length = length;
865 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
867 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
868 pa_silence_memchunk(target, &s->sample_spec);
872 vchunk = info[0].chunk;
873 pa_memblock_ref(vchunk.memblock);
875 if (vchunk.length > length)
876 vchunk.length = length;
878 if (!pa_cvolume_is_norm(&volume)) {
879 pa_memchunk_make_writable(&vchunk, 0);
880 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
883 pa_memchunk_memcpy(target, &vchunk);
884 pa_memblock_unref(vchunk.memblock);
890 ptr = pa_memblock_acquire(target->memblock);
892 target->length = pa_mix(info, n,
893 (uint8_t*) ptr + target->index, length,
895 &s->thread_info.soft_volume,
896 s->thread_info.soft_muted);
898 pa_memblock_release(target->memblock);
901 inputs_drop(s, info, n, target);
906 /* Called from IO thread context */
907 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
911 pa_sink_assert_ref(s);
912 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
914 pa_assert(target->memblock);
915 pa_assert(target->length > 0);
916 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
920 pa_assert(!s->thread_info.rewind_requested);
921 pa_assert(s->thread_info.rewind_nbytes == 0);
930 pa_sink_render_into(s, &chunk);
939 /* Called from IO thread context */
940 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
941 pa_mix_info info[MAX_MIX_CHANNELS];
942 size_t length1st = length;
945 pa_sink_assert_ref(s);
946 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
947 pa_assert(length > 0);
948 pa_assert(pa_frame_aligned(length, &s->sample_spec));
953 pa_assert(!s->thread_info.rewind_requested);
954 pa_assert(s->thread_info.rewind_nbytes == 0);
956 pa_assert(length > 0);
958 n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS);
961 pa_silence_memchunk_get(&s->core->silence_cache,
969 *result = info[0].chunk;
970 pa_memblock_ref(result->memblock);
972 if (result->length > length)
973 result->length = length;
975 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
977 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
978 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
979 pa_memblock_unref(result->memblock);
980 pa_silence_memchunk_get(&s->core->silence_cache,
986 pa_memchunk_make_writable(result, length);
987 pa_volume_memchunk(result, &s->sample_spec, &volume);
994 result->memblock = pa_memblock_new(s->core->mempool, length);
996 ptr = pa_memblock_acquire(result->memblock);
998 result->length = pa_mix(info, n,
999 (uint8_t*) ptr + result->index, length1st,
1001 &s->thread_info.soft_volume,
1002 s->thread_info.soft_muted);
1004 pa_memblock_release(result->memblock);
1007 inputs_drop(s, info, n, result);
1009 if (result->length < length) {
1012 pa_memchunk_make_writable(result, length);
1013 result->length = length;
1015 l = length - result->length;
1016 d = result->index + result->length;
1020 chunk.length -= d - result->index;
1022 pa_sink_render_into(s, &chunk);
1027 result->length = length;
1033 /* Called from main thread */
1034 pa_usec_t pa_sink_get_latency(pa_sink *s) {
1037 pa_sink_assert_ref(s);
1038 pa_assert(PA_SINK_IS_LINKED(s->state));
1040 /* The returned value is supposed to be in the time domain of the sound card! */
1042 if (s->state == PA_SINK_SUSPENDED)
1045 if (!(s->flags & PA_SINK_LATENCY))
1048 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
1053 /* Called from IO thread */
1054 pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s) {
1058 pa_sink_assert_ref(s);
1059 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1061 /* The returned value is supposed to be in the time domain of the sound card! */
1063 if (s->thread_info.state == PA_SINK_SUSPENDED)
1066 if (!(s->flags & PA_SINK_LATENCY))
1069 o = PA_MSGOBJECT(s);
1071 /* We probably should make this a proper vtable callback instead of going through process_msg() */
1073 if (o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1079 static void compute_new_soft_volume(pa_sink_input *i, const pa_cvolume *new_volume) {
1082 pa_sink_input_assert_ref(i);
1083 pa_assert(new_volume->channels == i->sample_spec.channels);
1086 * This basically calculates:
1088 * i->relative_volume := i->virtual_volume / new_volume
1089 * i->soft_volume := i->relative_volume * i->volume_factor
1092 /* The new sink volume passed in here must already be remapped to
1093 * the sink input's channel map! */
1095 i->soft_volume.channels = i->sample_spec.channels;
1097 for (c = 0; c < i->sample_spec.channels; c++)
1099 if (new_volume->values[c] <= PA_VOLUME_MUTED)
1100 /* We leave i->relative_volume untouched */
1101 i->soft_volume.values[c] = PA_VOLUME_MUTED;
1103 i->relative_volume[c] =
1104 pa_sw_volume_to_linear(i->virtual_volume.values[c]) /
1105 pa_sw_volume_to_linear(new_volume->values[c]);
1107 i->soft_volume.values[c] = pa_sw_volume_from_linear(
1108 i->relative_volume[c] *
1109 pa_sw_volume_to_linear(i->volume_factor.values[c]));
1112 /* Hooks have the ability to play games with i->soft_volume */
1113 pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1115 /* We don't copy the soft_volume to the thread_info data
1116 * here. That must be done by the caller */
1119 /* Called from main thread */
1120 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
1124 pa_sink_assert_ref(s);
1125 pa_assert(new_volume);
1126 pa_assert(PA_SINK_IS_LINKED(s->state));
1127 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1129 /* This is called whenever a sink input volume changes or a sink
1130 * input is added/removed and we might need to fix up the sink
1131 * volume accordingly. Please note that we don't actually update
1132 * the sinks volume here, we only return how it needs to be
1133 * updated. The caller should then call pa_sink_set_volume().*/
1135 if (pa_idxset_isempty(s->inputs)) {
1136 /* In the special case that we have no sink input we leave the
1137 * volume unmodified. */
1138 *new_volume = s->reference_volume;
1142 pa_cvolume_mute(new_volume, s->channel_map.channels);
1144 /* First let's determine the new maximum volume of all inputs
1145 * connected to this sink */
1146 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1148 pa_cvolume remapped_volume;
1150 remapped_volume = i->virtual_volume;
1151 pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
1153 for (c = 0; c < new_volume->channels; c++)
1154 if (remapped_volume.values[c] > new_volume->values[c])
1155 new_volume->values[c] = remapped_volume.values[c];
1158 /* Then, let's update the soft volumes of all inputs connected
1160 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1161 pa_cvolume remapped_new_volume;
1163 remapped_new_volume = *new_volume;
1164 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1165 compute_new_soft_volume(i, &remapped_new_volume);
1167 /* We don't copy soft_volume to the thread_info data here
1168 * (i.e. issue PA_SINK_INPUT_MESSAGE_SET_VOLUME) because we
1169 * want the update to be atomically with the sink volume
1170 * update, hence we do it within the pa_sink_set_volume() call
1175 /* Called from main thread */
1176 void pa_sink_propagate_flat_volume(pa_sink *s) {
1180 pa_sink_assert_ref(s);
1181 pa_assert(PA_SINK_IS_LINKED(s->state));
1182 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1184 /* This is called whenever the sink volume changes that is not
1185 * caused by a sink input volume change. We need to fix up the
1186 * sink input volumes accordingly */
1188 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1189 pa_cvolume sink_volume, new_virtual_volume;
1192 /* This basically calculates i->virtual_volume := i->relative_volume * s->virtual_volume */
1194 sink_volume = s->virtual_volume;
1195 pa_cvolume_remap(&sink_volume, &s->channel_map, &i->channel_map);
1197 for (c = 0; c < i->sample_spec.channels; c++)
1198 new_virtual_volume.values[c] = pa_sw_volume_from_linear(
1199 i->relative_volume[c] *
1200 pa_sw_volume_to_linear(sink_volume.values[c]));
1202 new_virtual_volume.channels = i->sample_spec.channels;
1204 if (!pa_cvolume_equal(&new_virtual_volume, &i->virtual_volume)) {
1205 i->virtual_volume = new_virtual_volume;
1207 /* Hmm, the soft volume might no longer actually match
1208 * what has been chosen as new virtual volume here,
1209 * especially when the old volume was
1210 * PA_VOLUME_MUTED. Hence let's recalculate the soft
1212 compute_new_soft_volume(i, &sink_volume);
1214 /* The virtual volume changed, let's tell people so */
1215 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1219 /* If the soft_volume of any of the sink inputs got changed, let's
1220 * make sure the thread copies are synced up. */
1221 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SYNC_VOLUMES, NULL, 0, NULL) == 0);
1224 /* Called from main thread */
1225 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference) {
1226 pa_bool_t virtual_volume_changed;
1228 pa_sink_assert_ref(s);
1229 pa_assert(PA_SINK_IS_LINKED(s->state));
1231 pa_assert(pa_cvolume_valid(volume));
1232 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1234 virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume);
1235 s->virtual_volume = *volume;
1237 if (become_reference)
1238 s->reference_volume = s->virtual_volume;
1240 /* Propagate this volume change back to the inputs */
1241 if (virtual_volume_changed)
1242 if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1243 pa_sink_propagate_flat_volume(s);
1245 if (s->set_volume) {
1246 /* If we have a function set_volume(), then we do not apply a
1247 * soft volume by default. However, set_volume() is free to
1248 * apply one to s->soft_volume */
1250 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1254 /* If we have no function set_volume(), then the soft volume
1255 * becomes the virtual volume */
1256 s->soft_volume = s->virtual_volume;
1258 /* This tells the sink that soft and/or virtual volume changed */
1260 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1262 if (virtual_volume_changed)
1263 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1266 /* Called from main thread. Only to be called by sink implementor */
1267 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1268 pa_sink_assert_ref(s);
1271 s->soft_volume = *volume;
1273 if (PA_SINK_IS_LINKED(s->state))
1274 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1276 s->thread_info.soft_volume = *volume;
1279 /* Called from main thread */
1280 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_bool_t reference) {
1281 pa_sink_assert_ref(s);
1283 if (s->refresh_volume || force_refresh) {
1284 struct pa_cvolume old_virtual_volume = s->virtual_volume;
1289 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1291 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1293 s->reference_volume = s->virtual_volume;
1295 if (s->flags & PA_SINK_FLAT_VOLUME)
1296 pa_sink_propagate_flat_volume(s);
1298 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1302 return reference ? &s->reference_volume : &s->virtual_volume;
1305 /* Called from main thread */
1306 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
1307 pa_sink_assert_ref(s);
1309 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1311 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
1314 s->reference_volume = s->virtual_volume = *new_volume;
1316 if (s->flags & PA_SINK_FLAT_VOLUME)
1317 pa_sink_propagate_flat_volume(s);
1319 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1322 /* Called from main thread */
1323 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1324 pa_bool_t old_muted;
1326 pa_sink_assert_ref(s);
1327 pa_assert(PA_SINK_IS_LINKED(s->state));
1329 old_muted = s->muted;
1335 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1337 if (old_muted != s->muted)
1338 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1341 /* Called from main thread */
1342 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1344 pa_sink_assert_ref(s);
1346 if (s->refresh_muted || force_refresh) {
1347 pa_bool_t old_muted = s->muted;
1352 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1354 if (old_muted != s->muted)
1355 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1361 /* Called from main thread */
1362 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
1363 pa_sink_assert_ref(s);
1365 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1367 if (s->muted == new_muted)
1370 s->muted = new_muted;
1371 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1374 /* Called from main thread */
1375 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1376 pa_sink_assert_ref(s);
1379 pa_proplist_update(s->proplist, mode, p);
1381 if (PA_SINK_IS_LINKED(s->state)) {
1382 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1383 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1389 /* Called from main thread */
1390 void pa_sink_set_description(pa_sink *s, const char *description) {
1392 pa_sink_assert_ref(s);
1394 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1397 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1399 if (old && description && !strcmp(old, description))
1403 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1405 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1407 if (s->monitor_source) {
1410 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1411 pa_source_set_description(s->monitor_source, n);
1415 if (PA_SINK_IS_LINKED(s->state)) {
1416 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1417 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1421 /* Called from main thread */
1422 unsigned pa_sink_linked_by(pa_sink *s) {
1425 pa_sink_assert_ref(s);
1426 pa_assert(PA_SINK_IS_LINKED(s->state));
1428 ret = pa_idxset_size(s->inputs);
1430 /* We add in the number of streams connected to us here. Please
1431 * note the asymmmetry to pa_sink_used_by()! */
1433 if (s->monitor_source)
1434 ret += pa_source_linked_by(s->monitor_source);
1439 /* Called from main thread */
1440 unsigned pa_sink_used_by(pa_sink *s) {
1443 pa_sink_assert_ref(s);
1444 pa_assert(PA_SINK_IS_LINKED(s->state));
1446 ret = pa_idxset_size(s->inputs);
1447 pa_assert(ret >= s->n_corked);
1449 /* Streams connected to our monitor source do not matter for
1450 * pa_sink_used_by()!.*/
1452 return ret - s->n_corked;
1455 /* Called from main thread */
1456 unsigned pa_sink_check_suspend(pa_sink *s) {
1461 pa_sink_assert_ref(s);
1463 if (!PA_SINK_IS_LINKED(s->state))
1468 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1469 pa_sink_input_state_t st;
1471 st = pa_sink_input_get_state(i);
1472 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1474 if (st == PA_SINK_INPUT_CORKED)
1477 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1483 if (s->monitor_source)
1484 ret += pa_source_check_suspend(s->monitor_source);
1489 /* Called from the IO thread */
1490 static void sync_input_volumes_within_thread(pa_sink *s) {
1494 pa_sink_assert_ref(s);
1496 while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1497 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1500 i->thread_info.soft_volume = i->soft_volume;
1501 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1505 /* Called from IO thread, except when it is not */
1506 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1507 pa_sink *s = PA_SINK(o);
1508 pa_sink_assert_ref(s);
1510 switch ((pa_sink_message_t) code) {
1512 case PA_SINK_MESSAGE_ADD_INPUT: {
1513 pa_sink_input *i = PA_SINK_INPUT(userdata);
1515 /* If you change anything here, make sure to change the
1516 * sink input handling a few lines down at
1517 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1519 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1521 /* Since the caller sleeps in pa_sink_input_put(), we can
1522 * safely access data outside of thread_info even though
1525 if ((i->thread_info.sync_prev = i->sync_prev)) {
1526 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1527 pa_assert(i->sync_prev->sync_next == i);
1528 i->thread_info.sync_prev->thread_info.sync_next = i;
1531 if ((i->thread_info.sync_next = i->sync_next)) {
1532 pa_assert(i->sink == i->thread_info.sync_next->sink);
1533 pa_assert(i->sync_next->sync_prev == i);
1534 i->thread_info.sync_next->thread_info.sync_prev = i;
1537 pa_assert(!i->thread_info.attached);
1538 i->thread_info.attached = TRUE;
1543 pa_sink_input_set_state_within_thread(i, i->state);
1545 /* The requested latency of the sink input needs to be
1546 * fixed up and then configured on the sink */
1548 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1549 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1551 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1552 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1554 /* We don't rewind here automatically. This is left to the
1555 * sink input implementor because some sink inputs need a
1556 * slow start, i.e. need some time to buffer client
1557 * samples before beginning streaming. */
1559 /* In flat volume mode we need to update the volume as
1561 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1564 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1565 pa_sink_input *i = PA_SINK_INPUT(userdata);
1567 /* If you change anything here, make sure to change the
1568 * sink input handling a few lines down at
1569 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1574 pa_sink_input_set_state_within_thread(i, i->state);
1576 pa_assert(i->thread_info.attached);
1577 i->thread_info.attached = FALSE;
1579 /* Since the caller sleeps in pa_sink_input_unlink(),
1580 * we can safely access data outside of thread_info even
1581 * though it is mutable */
1583 pa_assert(!i->sync_prev);
1584 pa_assert(!i->sync_next);
1586 if (i->thread_info.sync_prev) {
1587 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1588 i->thread_info.sync_prev = NULL;
1591 if (i->thread_info.sync_next) {
1592 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1593 i->thread_info.sync_next = NULL;
1596 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1597 pa_sink_input_unref(i);
1599 pa_sink_invalidate_requested_latency(s);
1600 pa_sink_request_rewind(s, (size_t) -1);
1602 /* In flat volume mode we need to update the volume as
1604 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1607 case PA_SINK_MESSAGE_START_MOVE: {
1608 pa_sink_input *i = PA_SINK_INPUT(userdata);
1610 /* We don't support moving synchronized streams. */
1611 pa_assert(!i->sync_prev);
1612 pa_assert(!i->sync_next);
1613 pa_assert(!i->thread_info.sync_next);
1614 pa_assert(!i->thread_info.sync_prev);
1616 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1618 size_t sink_nbytes, total_nbytes;
1620 /* Get the latency of the sink */
1621 if (!(s->flags & PA_SINK_LATENCY) ||
1622 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1625 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1626 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1628 if (total_nbytes > 0) {
1629 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1630 i->thread_info.rewrite_flush = TRUE;
1631 pa_sink_input_process_rewind(i, sink_nbytes);
1638 pa_assert(i->thread_info.attached);
1639 i->thread_info.attached = FALSE;
1641 /* Let's remove the sink input ...*/
1642 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1643 pa_sink_input_unref(i);
1645 pa_sink_invalidate_requested_latency(s);
1647 pa_log_debug("Requesting rewind due to started move");
1648 pa_sink_request_rewind(s, (size_t) -1);
1650 /* In flat volume mode we need to update the volume as
1652 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1655 case PA_SINK_MESSAGE_FINISH_MOVE: {
1656 pa_sink_input *i = PA_SINK_INPUT(userdata);
1658 /* We don't support moving synchronized streams. */
1659 pa_assert(!i->sync_prev);
1660 pa_assert(!i->sync_next);
1661 pa_assert(!i->thread_info.sync_next);
1662 pa_assert(!i->thread_info.sync_prev);
1664 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1666 pa_assert(!i->thread_info.attached);
1667 i->thread_info.attached = TRUE;
1672 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1673 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1675 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1676 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1678 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1682 /* Get the latency of the sink */
1683 if (!(s->flags & PA_SINK_LATENCY) ||
1684 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1687 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1690 pa_sink_input_drop(i, nbytes);
1692 pa_log_debug("Requesting rewind due to finished move");
1693 pa_sink_request_rewind(s, nbytes);
1696 /* In flat volume mode we need to update the volume as
1698 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1701 case PA_SINK_MESSAGE_SET_VOLUME:
1703 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1704 s->thread_info.soft_volume = s->soft_volume;
1705 pa_sink_request_rewind(s, (size_t) -1);
1708 if (!(s->flags & PA_SINK_FLAT_VOLUME))
1711 /* Fall through ... */
1713 case PA_SINK_MESSAGE_SYNC_VOLUMES:
1714 sync_input_volumes_within_thread(s);
1717 case PA_SINK_MESSAGE_GET_VOLUME:
1720 case PA_SINK_MESSAGE_SET_MUTE:
1722 if (s->thread_info.soft_muted != s->muted) {
1723 s->thread_info.soft_muted = s->muted;
1724 pa_sink_request_rewind(s, (size_t) -1);
1729 case PA_SINK_MESSAGE_GET_MUTE:
1732 case PA_SINK_MESSAGE_SET_STATE: {
1734 pa_bool_t suspend_change =
1735 (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
1736 (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED);
1738 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1740 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1741 s->thread_info.rewind_nbytes = 0;
1742 s->thread_info.rewind_requested = FALSE;
1745 if (suspend_change) {
1749 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1750 if (i->suspend_within_thread)
1751 i->suspend_within_thread(i, s->thread_info.state == PA_SINK_SUSPENDED);
1757 case PA_SINK_MESSAGE_DETACH:
1759 /* Detach all streams */
1760 pa_sink_detach_within_thread(s);
1763 case PA_SINK_MESSAGE_ATTACH:
1765 /* Reattach all streams */
1766 pa_sink_attach_within_thread(s);
1769 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1771 pa_usec_t *usec = userdata;
1772 *usec = pa_sink_get_requested_latency_within_thread(s);
1774 if (*usec == (pa_usec_t) -1)
1775 *usec = s->thread_info.max_latency;
1780 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1781 pa_usec_t *r = userdata;
1783 pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
1788 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1789 pa_usec_t *r = userdata;
1791 r[0] = s->thread_info.min_latency;
1792 r[1] = s->thread_info.max_latency;
1797 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1799 *((size_t*) userdata) = s->thread_info.max_rewind;
1802 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1804 *((size_t*) userdata) = s->thread_info.max_request;
1807 case PA_SINK_MESSAGE_SET_MAX_REWIND:
1809 pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
1812 case PA_SINK_MESSAGE_SET_MAX_REQUEST:
1814 pa_sink_set_max_request_within_thread(s, (size_t) offset);
1817 case PA_SINK_MESSAGE_GET_LATENCY:
1818 case PA_SINK_MESSAGE_MAX:
1825 /* Called from main thread */
1826 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1831 pa_core_assert_ref(c);
1833 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1836 if ((r = pa_sink_suspend(sink, suspend)) < 0)
1843 /* Called from main thread */
1844 void pa_sink_detach(pa_sink *s) {
1845 pa_sink_assert_ref(s);
1846 pa_assert(PA_SINK_IS_LINKED(s->state));
1848 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1851 /* Called from main thread */
1852 void pa_sink_attach(pa_sink *s) {
1853 pa_sink_assert_ref(s);
1854 pa_assert(PA_SINK_IS_LINKED(s->state));
1856 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1859 /* Called from IO thread */
1860 void pa_sink_detach_within_thread(pa_sink *s) {
1864 pa_sink_assert_ref(s);
1865 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1867 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1871 if (s->monitor_source)
1872 pa_source_detach_within_thread(s->monitor_source);
1875 /* Called from IO thread */
1876 void pa_sink_attach_within_thread(pa_sink *s) {
1880 pa_sink_assert_ref(s);
1881 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1883 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1887 if (s->monitor_source)
1888 pa_source_attach_within_thread(s->monitor_source);
1891 /* Called from IO thread */
1892 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1893 pa_sink_assert_ref(s);
1894 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1896 if (s->thread_info.state == PA_SINK_SUSPENDED)
1899 if (nbytes == (size_t) -1)
1900 nbytes = s->thread_info.max_rewind;
1902 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1904 if (s->thread_info.rewind_requested &&
1905 nbytes <= s->thread_info.rewind_nbytes)
1908 s->thread_info.rewind_nbytes = nbytes;
1909 s->thread_info.rewind_requested = TRUE;
1911 if (s->request_rewind)
1912 s->request_rewind(s);
1915 /* Called from IO thread */
1916 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1917 pa_usec_t result = (pa_usec_t) -1;
1920 pa_usec_t monitor_latency;
1922 pa_sink_assert_ref(s);
1924 if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
1925 return PA_CLAMP(s->fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
1927 if (s->thread_info.requested_latency_valid)
1928 return s->thread_info.requested_latency;
1930 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1932 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1933 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1934 result = i->thread_info.requested_sink_latency;
1936 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1938 if (monitor_latency != (pa_usec_t) -1 &&
1939 (result == (pa_usec_t) -1 || result > monitor_latency))
1940 result = monitor_latency;
1942 if (result != (pa_usec_t) -1)
1943 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
1945 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1946 /* Only cache if properly initialized */
1947 s->thread_info.requested_latency = result;
1948 s->thread_info.requested_latency_valid = TRUE;
1954 /* Called from main thread */
1955 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1958 pa_sink_assert_ref(s);
1959 pa_assert(PA_SINK_IS_LINKED(s->state));
1961 if (s->state == PA_SINK_SUSPENDED)
1964 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1968 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1969 void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
1973 pa_sink_assert_ref(s);
1975 if (max_rewind == s->thread_info.max_rewind)
1978 s->thread_info.max_rewind = max_rewind;
1980 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1981 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1982 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1985 if (s->monitor_source)
1986 pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
1989 /* Called from main thread */
1990 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1991 pa_sink_assert_ref(s);
1993 if (PA_SINK_IS_LINKED(s->state))
1994 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1996 pa_sink_set_max_rewind_within_thread(s, max_rewind);
1999 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
2000 void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
2003 pa_sink_assert_ref(s);
2005 if (max_request == s->thread_info.max_request)
2008 s->thread_info.max_request = max_request;
2010 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
2013 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
2014 pa_sink_input_update_max_request(i, s->thread_info.max_request);
2018 /* Called from main thread */
2019 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
2020 pa_sink_assert_ref(s);
2022 if (PA_SINK_IS_LINKED(s->state))
2023 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
2025 pa_sink_set_max_request_within_thread(s, max_request);
2028 /* Called from IO thread */
2029 void pa_sink_invalidate_requested_latency(pa_sink *s) {
2033 pa_sink_assert_ref(s);
2035 if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
2038 s->thread_info.requested_latency_valid = FALSE;
2040 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
2042 if (s->update_requested_latency)
2043 s->update_requested_latency(s);
2045 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
2046 if (i->update_sink_requested_latency)
2047 i->update_sink_requested_latency(i);
2051 /* Called from main thread */
2052 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
2053 pa_sink_assert_ref(s);
2055 /* min_latency == 0: no limit
2056 * min_latency anything else: specified limit
2058 * Similar for max_latency */
2060 if (min_latency < ABSOLUTE_MIN_LATENCY)
2061 min_latency = ABSOLUTE_MIN_LATENCY;
2063 if (max_latency <= 0 ||
2064 max_latency > ABSOLUTE_MAX_LATENCY)
2065 max_latency = ABSOLUTE_MAX_LATENCY;
2067 pa_assert(min_latency <= max_latency);
2069 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
2070 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
2071 max_latency == ABSOLUTE_MAX_LATENCY) ||
2072 (s->flags & PA_SINK_DYNAMIC_LATENCY));
2074 if (PA_SINK_IS_LINKED(s->state)) {
2080 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
2082 pa_sink_set_latency_range_within_thread(s, min_latency, max_latency);
2085 /* Called from main thread */
2086 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
2087 pa_sink_assert_ref(s);
2088 pa_assert(min_latency);
2089 pa_assert(max_latency);
2091 if (PA_SINK_IS_LINKED(s->state)) {
2092 pa_usec_t r[2] = { 0, 0 };
2094 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
2096 *min_latency = r[0];
2097 *max_latency = r[1];
2099 *min_latency = s->thread_info.min_latency;
2100 *max_latency = s->thread_info.max_latency;
2104 /* Called from IO thread */
2105 void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
2108 pa_sink_assert_ref(s);
2110 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
2111 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
2112 pa_assert(min_latency <= max_latency);
2114 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
2115 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
2116 max_latency == ABSOLUTE_MAX_LATENCY) ||
2117 (s->flags & PA_SINK_DYNAMIC_LATENCY));
2119 s->thread_info.min_latency = min_latency;
2120 s->thread_info.max_latency = max_latency;
2122 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
2125 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
2126 if (i->update_sink_latency_range)
2127 i->update_sink_latency_range(i);
2130 pa_sink_invalidate_requested_latency(s);
2132 pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
2135 /* Called from main thread, before the sink is put */
2136 void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
2137 pa_sink_assert_ref(s);
2139 pa_assert(pa_sink_get_state(s) == PA_SINK_INIT);
2141 if (latency < ABSOLUTE_MIN_LATENCY)
2142 latency = ABSOLUTE_MIN_LATENCY;
2144 if (latency > ABSOLUTE_MAX_LATENCY)
2145 latency = ABSOLUTE_MAX_LATENCY;
2147 s->fixed_latency = latency;
2148 pa_source_set_fixed_latency(s->monitor_source, latency);
2151 /* Called from main context */
2152 size_t pa_sink_get_max_rewind(pa_sink *s) {
2154 pa_sink_assert_ref(s);
2156 if (!PA_SINK_IS_LINKED(s->state))
2157 return s->thread_info.max_rewind;
2159 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
2164 /* Called from main context */
2165 size_t pa_sink_get_max_request(pa_sink *s) {
2167 pa_sink_assert_ref(s);
2169 if (!PA_SINK_IS_LINKED(s->state))
2170 return s->thread_info.max_request;
2172 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
2177 /* Called from main context */
2178 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
2179 const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
2183 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
2186 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
2188 if (pa_streq(ff, "microphone"))
2189 t = "audio-input-microphone";
2190 else if (pa_streq(ff, "webcam"))
2192 else if (pa_streq(ff, "computer"))
2194 else if (pa_streq(ff, "handset"))
2196 else if (pa_streq(ff, "portable"))
2197 t = "multimedia-player";
2198 else if (pa_streq(ff, "tv"))
2199 t = "video-display";
2203 if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2204 if (pa_streq(c, "modem"))
2211 t = "audio-input-microphone";
2214 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
2215 if (strstr(profile, "analog"))
2217 else if (strstr(profile, "iec958"))
2219 else if (strstr(profile, "hdmi"))
2223 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
2225 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
2230 pa_bool_t pa_device_init_description(pa_proplist *p) {
2234 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
2237 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
2238 if (pa_streq(s, "internal")) {
2239 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
2243 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2244 if (pa_streq(s, "modem")) {
2245 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
2249 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
2250 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);