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 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 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) {
60 memset(data, 0, sizeof(*data));
61 data->proplist = pa_proplist_new();
66 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *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) {
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) {
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) {
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) {
97 data->muted_is_set = TRUE;
101 void pa_sink_new_data_done(pa_sink_new_data *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) {
113 s->get_volume = NULL;
114 s->set_volume = NULL;
117 s->request_rewind = NULL;
118 s->update_requested_latency = NULL;
121 /* Called from main context */
122 pa_sink* pa_sink_new(
124 pa_sink_new_data *data,
125 pa_sink_flags_t flags) {
129 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
130 pa_source_new_data source_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))) {
145 pa_sink_new_data_set_name(data, name);
147 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
149 pa_namereg_unregister(core, name);
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)
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) {
181 pa_namereg_unregister(core, name);
185 s->parent.parent.free = sink_free;
186 s->parent.process_msg = pa_sink_process_msg;
189 s->state = PA_SINK_INIT;
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);
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;
216 pa_silence_memchunk_get(
217 &core->silence_cache,
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);
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",
245 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
246 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
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) {
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);
280 /* Called from main context */
281 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
283 pa_bool_t suspend_change;
284 pa_sink_state_t original_state;
288 if (s->state == state)
291 original_state = s->state;
294 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
295 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
298 if ((ret = s->set_state(s, state)) < 0)
302 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
305 s->set_state(s, original_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) {
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);
328 i->suspend(i, state == PA_SINK_SUSPENDED);
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) {
371 pa_sink_input *i, *j = NULL;
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
383 linked = PA_SINK_IS_LINKED(s->state);
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);
393 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
395 while ((i = pa_idxset_first(s->inputs, NULL))) {
397 pa_sink_input_kill(i);
402 sink_set_state(s, PA_SINK_UNLINKED);
404 s->state = PA_SINK_UNLINKED;
408 if (s->monitor_source)
409 pa_source_unlink(s->monitor_source);
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);
423 pa_assert(pa_sink_refcnt(s) == 0);
425 if (PA_SINK_IS_LINKED(s->state))
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);
449 pa_proplist_free(s->proplist);
454 /* Called from main context */
455 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
456 pa_sink_assert_ref(s);
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);
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)
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));
490 return sink_set_state(s, PA_SINK_SUSPENDED);
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) {
498 pa_sink_input *i, *n;
501 pa_sink_assert_ref(s);
502 pa_assert(PA_SINK_IS_LINKED(s->state));
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));
516 /* Called from main context */
517 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
520 pa_sink_assert_ref(s);
521 pa_assert(PA_SINK_IS_LINKED(s->state));
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) {
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) {
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)
561 s->thread_info.rewind_nbytes = 0;
562 s->thread_info.rewind_requested = FALSE;
564 if (s->thread_info.state == PA_SINK_SUSPENDED)
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);
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) {
585 size_t mixlength = *length;
587 pa_sink_assert_ref(s);
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);
603 info->userdata = pa_sink_input_ref(i);
605 pa_assert(info->chunk.memblock);
606 pa_assert(info->chunk.length > 0);
619 /* Called from IO thread context */
620 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
624 unsigned n_unreffed = 0;
626 pa_sink_assert_ref(s);
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))) {
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) {
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) {
662 if (m && m->chunk.memblock) {
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);
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);
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);
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--) {
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];
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));
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);
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);
751 *result = s->silence;
752 pa_memblock_ref(result->memblock);
754 if (result->length > length)
755 result->length = length;
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);
773 pa_volume_memchunk(result, &s->sample_spec, &volume);
777 result->memblock = pa_memblock_new(s->core->mempool, length);
779 ptr = pa_memblock_acquire(result->memblock);
780 result->length = pa_mix(info, n,
783 &s->thread_info.soft_volume,
784 s->thread_info.soft_muted);
785 pa_memblock_release(result->memblock);
790 inputs_drop(s, info, n, result);
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];
799 size_t length, block_size_max;
801 pa_sink_assert_ref(s);
802 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
804 pa_assert(target->memblock);
805 pa_assert(target->length > 0);
806 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
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);
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);
828 if (target->length > length)
829 target->length = length;
831 pa_silence_memchunk(target, &s->sample_spec);
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);
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);
863 ptr = pa_memblock_acquire(target->memblock);
865 target->length = pa_mix(info, n,
866 (uint8_t*) ptr + target->index, length,
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);
879 /* Called from IO thread context */
880 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
884 pa_sink_assert_ref(s);
885 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
887 pa_assert(target->memblock);
888 pa_assert(target->length > 0);
889 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
893 pa_assert(!s->thread_info.rewind_requested);
894 pa_assert(s->thread_info.rewind_nbytes == 0);
903 pa_sink_render_into(s, &chunk);
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));
920 pa_assert(!s->thread_info.rewind_requested);
921 pa_assert(s->thread_info.rewind_nbytes == 0);
923 /*** This needs optimization ***/
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) {
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)
944 if (!(s->flags & PA_SINK_LATENCY))
947 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
952 /* Called from main thread */
953 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
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;
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))) {
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
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) {
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;
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;
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));
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);
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 */
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);
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);
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;
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;
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;
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);
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);
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);
1189 /* Called from main thread */
1190 void pa_sink_set_description(pa_sink *s, const char *description) {
1192 pa_sink_assert_ref(s);
1194 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1197 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1199 if (old && description && !strcmp(old, description))
1203 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1205 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1207 if (s->monitor_source) {
1210 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1211 pa_source_set_description(s->monitor_source, 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) {
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);
1239 /* Called from main thread */
1240 unsigned pa_sink_used_by(pa_sink *s) {
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) {
1261 pa_sink_assert_ref(s);
1263 if (!PA_SINK_IS_LINKED(s->state))
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)
1277 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1283 if (s->monitor_source)
1284 ret += pa_source_check_suspend(s->monitor_source);
1289 /* Called from the IO thread */
1290 static void sync_input_volumes_within_thread(pa_sink *s) {
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))
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
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;
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
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. */
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
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) {
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)
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);
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
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;
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) {
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)
1487 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
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
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);
1513 case PA_SINK_MESSAGE_GET_VOLUME:
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);
1525 case PA_SINK_MESSAGE_GET_MUTE:
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;
1537 case PA_SINK_MESSAGE_DETACH:
1539 /* Detach all streams */
1540 pa_sink_detach_within_thread(s);
1543 case PA_SINK_MESSAGE_ATTACH:
1545 /* Reattach all streams */
1546 pa_sink_attach_within_thread(s);
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;
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]);
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;
1577 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1579 *((size_t*) userdata) = s->thread_info.max_rewind;
1582 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1584 *((size_t*) userdata) = s->thread_info.max_request;
1587 case PA_SINK_MESSAGE_GET_LATENCY:
1588 case PA_SINK_MESSAGE_MAX:
1595 /* Called from main thread */
1596 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
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;
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) {
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)))
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) {
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)))
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)
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)
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;
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;
1719 /* Called from main thread */
1720 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1723 pa_sink_assert_ref(s);
1724 pa_assert(PA_SINK_IS_LINKED(s->state));
1726 if (s->state == PA_SINK_SUSPENDED)
1729 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1733 /* Called from IO thread */
1734 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1738 pa_sink_assert_ref(s);
1740 if (max_rewind == s->thread_info.max_rewind)
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) {
1758 pa_sink_assert_ref(s);
1760 if (max_request == s->thread_info.max_request)
1763 s->thread_info.max_request = max_request;
1765 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
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) {
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)) {
1815 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
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];
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) {
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) {
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);
1881 /* Called from main context */
1882 size_t pa_sink_get_max_request(pa_sink *s) {
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);
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;
1900 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
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"))
1909 else if (pa_streq(ff, "computer"))
1911 else if (pa_streq(ff, "handset"))
1919 t = "audio-input-microphone";
1922 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
1923 if (strstr(profile, "analog"))
1925 else if (strstr(profile, "iec958"))
1927 else if (strstr(profile, "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));
1938 pa_bool_t pa_device_init_description(pa_proplist *p) {
1942 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
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"));
1951 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
1952 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);