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 DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
53 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
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->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;
218 pa_silence_memchunk_get(
219 &core->silence_cache,
225 s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
226 s->thread_info.soft_volume = s->soft_volume;
227 s->thread_info.soft_muted = s->muted;
228 s->thread_info.state = s->state;
229 s->thread_info.rewind_nbytes = 0;
230 s->thread_info.rewind_requested = FALSE;
231 s->thread_info.max_rewind = 0;
232 s->thread_info.max_request = 0;
233 s->thread_info.requested_latency_valid = FALSE;
234 s->thread_info.requested_latency = 0;
235 s->thread_info.min_latency = DEFAULT_MIN_LATENCY;
236 s->thread_info.max_latency = DEFAULT_MIN_LATENCY;
238 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
241 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
243 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
244 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
247 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
248 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
252 pa_source_new_data_init(&source_data);
253 pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
254 pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
255 source_data.name = pa_sprintf_malloc("%s.monitor", name);
256 source_data.driver = data->driver;
257 source_data.module = data->module;
258 source_data.card = data->card;
260 dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
261 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
262 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
264 s->monitor_source = pa_source_new(core, &source_data, PA_SOURCE_LATENCY);
266 pa_source_new_data_done(&source_data);
268 if (!s->monitor_source) {
274 s->monitor_source->monitor_of = s;
276 pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
277 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
282 /* Called from main context */
283 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
285 pa_bool_t suspend_change;
286 pa_sink_state_t original_state;
290 if (s->state == state)
293 original_state = s->state;
296 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
297 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
300 if ((ret = s->set_state(s, state)) < 0)
304 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
307 s->set_state(s, original_state);
314 if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
315 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
316 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
319 if (suspend_change) {
323 /* We're suspending or resuming, tell everyone about it */
325 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
326 if (s->state == PA_SINK_SUSPENDED &&
327 (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
328 pa_sink_input_kill(i);
330 i->suspend(i, state == PA_SINK_SUSPENDED);
332 if (s->monitor_source)
333 pa_source_sync_suspend(s->monitor_source);
339 /* Called from main context */
340 void pa_sink_put(pa_sink* s) {
341 pa_sink_assert_ref(s);
343 pa_assert(s->state == PA_SINK_INIT);
345 /* The following fields must be initialized properly when calling _put() */
346 pa_assert(s->asyncmsgq);
347 pa_assert(s->rtpoll);
348 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
350 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
351 s->flags |= PA_SINK_DECIBEL_VOLUME;
353 s->thread_info.soft_volume = s->soft_volume;
354 s->thread_info.soft_muted = s->muted;
357 if (s->flags & PA_SINK_DECIBEL_VOLUME)
358 s->n_volume_steps = PA_VOLUME_NORM+1;
360 if (s->core->flat_volumes)
361 if (s->flags & PA_SINK_DECIBEL_VOLUME)
362 s->flags |= PA_SINK_FLAT_VOLUME;
364 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
366 pa_source_put(s->monitor_source);
368 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
369 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
372 /* Called from main context */
373 void pa_sink_unlink(pa_sink* s) {
375 pa_sink_input *i, *j = NULL;
379 /* Please note that pa_sink_unlink() does more than simply
380 * reversing pa_sink_put(). It also undoes the registrations
381 * already done in pa_sink_new()! */
383 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
384 * may be called multiple times on the same sink without bad
387 linked = PA_SINK_IS_LINKED(s->state);
390 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
392 if (s->state != PA_SINK_UNLINKED)
393 pa_namereg_unregister(s->core, s->name);
394 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
397 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
399 while ((i = pa_idxset_first(s->inputs, NULL))) {
401 pa_sink_input_kill(i);
406 sink_set_state(s, PA_SINK_UNLINKED);
408 s->state = PA_SINK_UNLINKED;
412 if (s->monitor_source)
413 pa_source_unlink(s->monitor_source);
416 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
417 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
421 /* Called from main context */
422 static void sink_free(pa_object *o) {
423 pa_sink *s = PA_SINK(o);
427 pa_assert(pa_sink_refcnt(s) == 0);
429 if (PA_SINK_IS_LINKED(s->state))
432 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
434 if (s->monitor_source) {
435 pa_source_unref(s->monitor_source);
436 s->monitor_source = NULL;
439 pa_idxset_free(s->inputs, NULL, NULL);
441 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
442 pa_sink_input_unref(i);
444 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
446 if (s->silence.memblock)
447 pa_memblock_unref(s->silence.memblock);
453 pa_proplist_free(s->proplist);
458 /* Called from main context */
459 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
460 pa_sink_assert_ref(s);
464 if (s->monitor_source)
465 pa_source_set_asyncmsgq(s->monitor_source, q);
468 /* Called from main context */
469 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
470 pa_sink_assert_ref(s);
473 if (s->monitor_source)
474 pa_source_set_rtpoll(s->monitor_source, p);
477 /* Called from main context */
478 int pa_sink_update_status(pa_sink*s) {
479 pa_sink_assert_ref(s);
480 pa_assert(PA_SINK_IS_LINKED(s->state));
482 if (s->state == PA_SINK_SUSPENDED)
485 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
488 /* Called from main context */
489 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
490 pa_sink_assert_ref(s);
491 pa_assert(PA_SINK_IS_LINKED(s->state));
494 return sink_set_state(s, PA_SINK_SUSPENDED);
496 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
499 /* Called from main context */
500 pa_queue *pa_sink_move_all_start(pa_sink *s) {
502 pa_sink_input *i, *n;
505 pa_sink_assert_ref(s);
506 pa_assert(PA_SINK_IS_LINKED(s->state));
510 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
511 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
513 if (pa_sink_input_start_move(i) >= 0)
514 pa_queue_push(q, pa_sink_input_ref(i));
520 /* Called from main context */
521 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
524 pa_sink_assert_ref(s);
525 pa_assert(PA_SINK_IS_LINKED(s->state));
528 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
529 if (pa_sink_input_finish_move(i, s, save) < 0)
530 pa_sink_input_kill(i);
532 pa_sink_input_unref(i);
535 pa_queue_free(q, NULL, NULL);
538 /* Called from main context */
539 void pa_sink_move_all_fail(pa_queue *q) {
543 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
544 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
545 pa_sink_input_kill(i);
546 pa_sink_input_unref(i);
550 pa_queue_free(q, NULL, NULL);
553 /* Called from IO thread context */
554 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
557 pa_sink_assert_ref(s);
558 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
560 /* If nobody requested this and this is actually no real rewind
561 * then we can short cut this */
562 if (!s->thread_info.rewind_requested && nbytes <= 0)
565 s->thread_info.rewind_nbytes = 0;
566 s->thread_info.rewind_requested = FALSE;
568 if (s->thread_info.state == PA_SINK_SUSPENDED)
572 pa_log_debug("Processing rewind...");
574 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
575 pa_sink_input_assert_ref(i);
576 pa_sink_input_process_rewind(i, nbytes);
580 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
581 pa_source_process_rewind(s->monitor_source, nbytes);
584 /* Called from IO thread context */
585 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
589 size_t mixlength = *length;
591 pa_sink_assert_ref(s);
594 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
595 pa_sink_input_assert_ref(i);
597 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
599 if (mixlength == 0 || info->chunk.length < mixlength)
600 mixlength = info->chunk.length;
602 if (pa_memblock_is_silence(info->chunk.memblock)) {
603 pa_memblock_unref(info->chunk.memblock);
607 info->userdata = pa_sink_input_ref(i);
609 pa_assert(info->chunk.memblock);
610 pa_assert(info->chunk.length > 0);
623 /* Called from IO thread context */
624 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
628 unsigned n_unreffed = 0;
630 pa_sink_assert_ref(s);
632 pa_assert(result->memblock);
633 pa_assert(result->length > 0);
635 /* We optimize for the case where the order of the inputs has not changed */
637 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
639 pa_mix_info* m = NULL;
641 pa_sink_input_assert_ref(i);
643 /* Let's try to find the matching entry info the pa_mix_info array */
644 for (j = 0; j < n; j ++) {
646 if (info[p].userdata == i) {
657 pa_sink_input_drop(i, result->length);
659 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
661 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
666 if (m && m->chunk.memblock) {
668 pa_memblock_ref(c.memblock);
669 pa_assert(result->length <= c.length);
670 c.length = result->length;
672 pa_memchunk_make_writable(&c, 0);
673 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
676 pa_memblock_ref(c.memblock);
677 pa_assert(result->length <= c.length);
678 c.length = result->length;
681 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
682 pa_source_output_assert_ref(o);
683 pa_assert(o->direct_on_input == i);
684 pa_source_post_direct(s->monitor_source, o, &c);
687 pa_memblock_unref(c.memblock);
692 if (m->chunk.memblock)
693 pa_memblock_unref(m->chunk.memblock);
694 pa_memchunk_reset(&m->chunk);
696 pa_sink_input_unref(m->userdata);
703 /* Now drop references to entries that are included in the
704 * pa_mix_info array but don't exist anymore */
706 if (n_unreffed < n) {
707 for (; n > 0; info++, n--) {
709 pa_sink_input_unref(info->userdata);
710 if (info->chunk.memblock)
711 pa_memblock_unref(info->chunk.memblock);
715 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
716 pa_source_post(s->monitor_source, result);
719 /* Called from IO thread context */
720 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
721 pa_mix_info info[MAX_MIX_CHANNELS];
723 size_t block_size_max;
725 pa_sink_assert_ref(s);
726 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
727 pa_assert(pa_frame_aligned(length, &s->sample_spec));
732 pa_assert(!s->thread_info.rewind_requested);
733 pa_assert(s->thread_info.rewind_nbytes == 0);
735 if (s->thread_info.state == PA_SINK_SUSPENDED) {
736 result->memblock = pa_memblock_ref(s->silence.memblock);
737 result->index = s->silence.index;
738 result->length = PA_MIN(s->silence.length, length);
743 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
745 block_size_max = pa_mempool_block_size_max(s->core->mempool);
746 if (length > block_size_max)
747 length = pa_frame_align(block_size_max, &s->sample_spec);
749 pa_assert(length > 0);
751 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
755 *result = s->silence;
756 pa_memblock_ref(result->memblock);
758 if (result->length > length)
759 result->length = length;
764 *result = info[0].chunk;
765 pa_memblock_ref(result->memblock);
767 if (result->length > length)
768 result->length = length;
770 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
772 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
773 pa_memchunk_make_writable(result, 0);
774 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
775 pa_silence_memchunk(result, &s->sample_spec);
777 pa_volume_memchunk(result, &s->sample_spec, &volume);
781 result->memblock = pa_memblock_new(s->core->mempool, length);
783 ptr = pa_memblock_acquire(result->memblock);
784 result->length = pa_mix(info, n,
787 &s->thread_info.soft_volume,
788 s->thread_info.soft_muted);
789 pa_memblock_release(result->memblock);
794 inputs_drop(s, info, n, result);
799 /* Called from IO thread context */
800 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
801 pa_mix_info info[MAX_MIX_CHANNELS];
803 size_t length, block_size_max;
805 pa_sink_assert_ref(s);
806 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
808 pa_assert(target->memblock);
809 pa_assert(target->length > 0);
810 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
814 pa_assert(!s->thread_info.rewind_requested);
815 pa_assert(s->thread_info.rewind_nbytes == 0);
817 if (s->thread_info.state == PA_SINK_SUSPENDED) {
818 pa_silence_memchunk(target, &s->sample_spec);
822 length = target->length;
823 block_size_max = pa_mempool_block_size_max(s->core->mempool);
824 if (length > block_size_max)
825 length = pa_frame_align(block_size_max, &s->sample_spec);
827 pa_assert(length > 0);
829 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
832 if (target->length > length)
833 target->length = length;
835 pa_silence_memchunk(target, &s->sample_spec);
839 if (target->length > length)
840 target->length = length;
842 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
844 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
845 pa_silence_memchunk(target, &s->sample_spec);
849 vchunk = info[0].chunk;
850 pa_memblock_ref(vchunk.memblock);
852 if (vchunk.length > length)
853 vchunk.length = length;
855 if (!pa_cvolume_is_norm(&volume)) {
856 pa_memchunk_make_writable(&vchunk, 0);
857 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
860 pa_memchunk_memcpy(target, &vchunk);
861 pa_memblock_unref(vchunk.memblock);
867 ptr = pa_memblock_acquire(target->memblock);
869 target->length = pa_mix(info, n,
870 (uint8_t*) ptr + target->index, length,
872 &s->thread_info.soft_volume,
873 s->thread_info.soft_muted);
875 pa_memblock_release(target->memblock);
878 inputs_drop(s, info, n, target);
883 /* Called from IO thread context */
884 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
888 pa_sink_assert_ref(s);
889 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
891 pa_assert(target->memblock);
892 pa_assert(target->length > 0);
893 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
897 pa_assert(!s->thread_info.rewind_requested);
898 pa_assert(s->thread_info.rewind_nbytes == 0);
907 pa_sink_render_into(s, &chunk);
916 /* Called from IO thread context */
917 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
918 pa_sink_assert_ref(s);
919 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
920 pa_assert(length > 0);
921 pa_assert(pa_frame_aligned(length, &s->sample_spec));
924 pa_assert(!s->thread_info.rewind_requested);
925 pa_assert(s->thread_info.rewind_nbytes == 0);
927 /*** This needs optimization ***/
930 result->length = length;
931 result->memblock = pa_memblock_new(s->core->mempool, length);
933 pa_sink_render_into_full(s, result);
936 /* Called from main thread */
937 pa_usec_t pa_sink_get_latency(pa_sink *s) {
940 pa_sink_assert_ref(s);
941 pa_assert(PA_SINK_IS_LINKED(s->state));
943 /* The returned value is supposed to be in the time domain of the sound card! */
945 if (s->state == PA_SINK_SUSPENDED)
948 if (!(s->flags & PA_SINK_LATENCY))
951 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
956 /* Called from main thread */
957 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
961 pa_sink_assert_ref(s);
962 pa_assert(new_volume);
963 pa_assert(PA_SINK_IS_LINKED(s->state));
964 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
966 /* This is called whenever a sink input volume changes and we
967 * might need to fix up the sink volume accordingly. Please note
968 * that we don't actually update the sinks volume here, we only
969 * return how it needs to be updated. The caller should then call
970 * pa_sink_set_flat_volume().*/
972 if (pa_idxset_isempty(s->inputs)) {
973 /* In the special case that we have no sink input we leave the
974 * volume unmodified. */
975 *new_volume = s->virtual_volume;
979 pa_cvolume_mute(new_volume, s->channel_map.channels);
981 /* First let's determine the new maximum volume of all inputs
982 * connected to this sink */
983 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
985 pa_cvolume remapped_volume;
987 remapped_volume = i->virtual_volume;
988 pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
990 for (c = 0; c < new_volume->channels; c++)
991 if (remapped_volume.values[c] > new_volume->values[c])
992 new_volume->values[c] = remapped_volume.values[c];
995 /* Then, let's update the soft volumes of all inputs connected
997 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
998 pa_cvolume remapped_new_volume;
1000 remapped_new_volume = *new_volume;
1001 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1002 pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
1003 pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor);
1005 /* Hooks have the ability to play games with i->soft_volume */
1006 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1008 /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
1009 * we want the update to have atomically with the sink
1010 * volume update, hence we do it within the
1011 * pa_sink_set_flat_volume() call below*/
1015 /* Called from main thread */
1016 void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
1020 pa_sink_assert_ref(s);
1021 pa_assert(old_volume);
1022 pa_assert(PA_SINK_IS_LINKED(s->state));
1023 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1025 /* This is called whenever the sink volume changes that is not
1026 * caused by a sink input volume change. We need to fix up the
1027 * sink input volumes accordingly */
1029 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1030 pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
1033 remapped_new_volume = s->virtual_volume;
1034 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1036 remapped_old_volume = *old_volume;
1037 pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
1039 for (c = 0; c < i->sample_spec.channels; c++)
1041 if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
1042 fixed_volume.values[c] = PA_VOLUME_MUTED;
1044 fixed_volume.values[c] = (pa_volume_t)
1045 ((uint64_t) i->virtual_volume.values[c] *
1046 (uint64_t) remapped_new_volume.values[c] /
1047 (uint64_t) remapped_old_volume.values[c]);
1049 fixed_volume.channels = i->virtual_volume.channels;
1051 if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
1052 i->virtual_volume = fixed_volume;
1054 /* The virtual volume changed, let's tell people so */
1055 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1060 /* Called from main thread */
1061 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1062 pa_cvolume old_virtual_volume;
1063 pa_bool_t virtual_volume_changed;
1065 pa_sink_assert_ref(s);
1066 pa_assert(PA_SINK_IS_LINKED(s->state));
1068 pa_assert(pa_cvolume_valid(volume));
1069 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1071 old_virtual_volume = s->virtual_volume;
1072 s->virtual_volume = *volume;
1073 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
1075 /* Propagate this volume change back to the inputs */
1076 if (virtual_volume_changed)
1077 if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1078 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1080 if (s->set_volume) {
1081 /* If we have a function set_volume(), then we do not apply a
1082 * soft volume by default. However, set_volume() is apply one
1083 * to s->soft_volume */
1085 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1089 /* If we have no function set_volume(), then the soft volume
1090 * becomes the virtual volume */
1091 s->soft_volume = s->virtual_volume;
1093 /* This tells the sink that soft and/or virtual volume changed */
1095 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1097 if (virtual_volume_changed)
1098 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1101 /* Called from main thread. Only to be called by sink implementor */
1102 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1103 pa_sink_assert_ref(s);
1106 s->soft_volume = *volume;
1108 if (PA_SINK_IS_LINKED(s->state))
1109 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1111 s->thread_info.soft_volume = *volume;
1114 /* Called from main thread */
1115 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1116 pa_sink_assert_ref(s);
1118 if (s->refresh_volume || force_refresh) {
1119 struct pa_cvolume old_virtual_volume = s->virtual_volume;
1124 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1126 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1128 if (s->flags & PA_SINK_FLAT_VOLUME)
1129 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1131 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1135 return &s->virtual_volume;
1138 /* Called from main thread */
1139 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
1140 pa_sink_assert_ref(s);
1142 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1144 if (pa_cvolume_equal(&s->virtual_volume, new_volume))
1147 s->virtual_volume = *new_volume;
1148 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1151 /* Called from main thread */
1152 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1153 pa_bool_t old_muted;
1155 pa_sink_assert_ref(s);
1156 pa_assert(PA_SINK_IS_LINKED(s->state));
1158 old_muted = s->muted;
1164 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1166 if (old_muted != s->muted)
1167 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1170 /* Called from main thread */
1171 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1173 pa_sink_assert_ref(s);
1175 if (s->refresh_muted || force_refresh) {
1176 pa_bool_t old_muted = s->muted;
1181 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1183 if (old_muted != s->muted)
1184 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1190 /* Called from main thread */
1191 void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
1192 pa_sink_assert_ref(s);
1194 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
1196 if (s->muted == new_muted)
1199 s->muted = new_muted;
1200 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1203 /* Called from main thread */
1204 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1205 pa_sink_assert_ref(s);
1208 pa_proplist_update(s->proplist, mode, p);
1210 if (PA_SINK_IS_LINKED(s->state)) {
1211 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1212 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1218 /* Called from main thread */
1219 void pa_sink_set_description(pa_sink *s, const char *description) {
1221 pa_sink_assert_ref(s);
1223 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1226 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1228 if (old && description && !strcmp(old, description))
1232 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1234 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1236 if (s->monitor_source) {
1239 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1240 pa_source_set_description(s->monitor_source, n);
1244 if (PA_SINK_IS_LINKED(s->state)) {
1245 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1246 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1250 /* Called from main thread */
1251 unsigned pa_sink_linked_by(pa_sink *s) {
1254 pa_sink_assert_ref(s);
1255 pa_assert(PA_SINK_IS_LINKED(s->state));
1257 ret = pa_idxset_size(s->inputs);
1259 /* We add in the number of streams connected to us here. Please
1260 * note the asymmmetry to pa_sink_used_by()! */
1262 if (s->monitor_source)
1263 ret += pa_source_linked_by(s->monitor_source);
1268 /* Called from main thread */
1269 unsigned pa_sink_used_by(pa_sink *s) {
1272 pa_sink_assert_ref(s);
1273 pa_assert(PA_SINK_IS_LINKED(s->state));
1275 ret = pa_idxset_size(s->inputs);
1276 pa_assert(ret >= s->n_corked);
1278 /* Streams connected to our monitor source do not matter for
1279 * pa_sink_used_by()!.*/
1281 return ret - s->n_corked;
1284 /* Called from main thread */
1285 unsigned pa_sink_check_suspend(pa_sink *s) {
1290 pa_sink_assert_ref(s);
1292 if (!PA_SINK_IS_LINKED(s->state))
1297 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1298 pa_sink_input_state_t st;
1300 st = pa_sink_input_get_state(i);
1301 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1303 if (st == PA_SINK_INPUT_CORKED)
1306 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1312 if (s->monitor_source)
1313 ret += pa_source_check_suspend(s->monitor_source);
1318 /* Called from the IO thread */
1319 static void sync_input_volumes_within_thread(pa_sink *s) {
1323 pa_sink_assert_ref(s);
1325 while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1326 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1329 i->thread_info.soft_volume = i->soft_volume;
1330 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1334 /* Called from IO thread, except when it is not */
1335 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1336 pa_sink *s = PA_SINK(o);
1337 pa_sink_assert_ref(s);
1339 switch ((pa_sink_message_t) code) {
1341 case PA_SINK_MESSAGE_ADD_INPUT: {
1342 pa_sink_input *i = PA_SINK_INPUT(userdata);
1344 /* If you change anything here, make sure to change the
1345 * sink input handling a few lines down at
1346 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1348 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1350 /* Since the caller sleeps in pa_sink_input_put(), we can
1351 * safely access data outside of thread_info even though
1354 if ((i->thread_info.sync_prev = i->sync_prev)) {
1355 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1356 pa_assert(i->sync_prev->sync_next == i);
1357 i->thread_info.sync_prev->thread_info.sync_next = i;
1360 if ((i->thread_info.sync_next = i->sync_next)) {
1361 pa_assert(i->sink == i->thread_info.sync_next->sink);
1362 pa_assert(i->sync_next->sync_prev == i);
1363 i->thread_info.sync_next->thread_info.sync_prev = i;
1366 pa_assert(!i->thread_info.attached);
1367 i->thread_info.attached = TRUE;
1372 pa_sink_input_set_state_within_thread(i, i->state);
1374 /* The requested latency of the sink input needs to be
1375 * fixed up and then configured on the sink */
1377 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1378 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1380 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1381 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1383 /* We don't rewind here automatically. This is left to the
1384 * sink input implementor because some sink inputs need a
1385 * slow start, i.e. need some time to buffer client
1386 * samples before beginning streaming. */
1388 /* In flat volume mode we need to update the volume as
1390 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1393 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1394 pa_sink_input *i = PA_SINK_INPUT(userdata);
1396 /* If you change anything here, make sure to change the
1397 * sink input handling a few lines down at
1398 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1403 pa_sink_input_set_state_within_thread(i, i->state);
1405 pa_assert(i->thread_info.attached);
1406 i->thread_info.attached = FALSE;
1408 /* Since the caller sleeps in pa_sink_input_unlink(),
1409 * we can safely access data outside of thread_info even
1410 * though it is mutable */
1412 pa_assert(!i->sync_prev);
1413 pa_assert(!i->sync_next);
1415 if (i->thread_info.sync_prev) {
1416 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1417 i->thread_info.sync_prev = NULL;
1420 if (i->thread_info.sync_next) {
1421 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1422 i->thread_info.sync_next = NULL;
1425 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1426 pa_sink_input_unref(i);
1428 pa_sink_invalidate_requested_latency(s);
1429 pa_sink_request_rewind(s, (size_t) -1);
1431 /* In flat volume mode we need to update the volume as
1433 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1436 case PA_SINK_MESSAGE_START_MOVE: {
1437 pa_sink_input *i = PA_SINK_INPUT(userdata);
1439 /* We don't support moving synchronized streams. */
1440 pa_assert(!i->sync_prev);
1441 pa_assert(!i->sync_next);
1442 pa_assert(!i->thread_info.sync_next);
1443 pa_assert(!i->thread_info.sync_prev);
1445 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1447 size_t sink_nbytes, total_nbytes;
1449 /* Get the latency of the sink */
1450 if (!(s->flags & PA_SINK_LATENCY) ||
1451 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1454 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1455 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1457 if (total_nbytes > 0) {
1458 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1459 i->thread_info.rewrite_flush = TRUE;
1460 pa_sink_input_process_rewind(i, sink_nbytes);
1467 pa_assert(i->thread_info.attached);
1468 i->thread_info.attached = FALSE;
1470 /* Let's remove the sink input ...*/
1471 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1472 pa_sink_input_unref(i);
1474 pa_sink_invalidate_requested_latency(s);
1476 pa_log_debug("Requesting rewind due to started move");
1477 pa_sink_request_rewind(s, (size_t) -1);
1479 /* In flat volume mode we need to update the volume as
1481 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1484 case PA_SINK_MESSAGE_FINISH_MOVE: {
1485 pa_sink_input *i = PA_SINK_INPUT(userdata);
1487 /* We don't support moving synchronized streams. */
1488 pa_assert(!i->sync_prev);
1489 pa_assert(!i->sync_next);
1490 pa_assert(!i->thread_info.sync_next);
1491 pa_assert(!i->thread_info.sync_prev);
1493 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1495 pa_assert(!i->thread_info.attached);
1496 i->thread_info.attached = TRUE;
1501 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1502 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1504 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1505 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1507 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1511 /* Get the latency of the sink */
1512 if (!(s->flags & PA_SINK_LATENCY) ||
1513 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1516 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1519 pa_sink_input_drop(i, nbytes);
1521 pa_log_debug("Requesting rewind due to finished move");
1522 pa_sink_request_rewind(s, nbytes);
1525 /* In flat volume mode we need to update the volume as
1527 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1530 case PA_SINK_MESSAGE_SET_VOLUME:
1532 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1533 s->thread_info.soft_volume = s->soft_volume;
1534 pa_sink_request_rewind(s, (size_t) -1);
1537 if (s->flags & PA_SINK_FLAT_VOLUME)
1538 sync_input_volumes_within_thread(s);
1542 case PA_SINK_MESSAGE_GET_VOLUME:
1545 case PA_SINK_MESSAGE_SET_MUTE:
1547 if (s->thread_info.soft_muted != s->muted) {
1548 s->thread_info.soft_muted = s->muted;
1549 pa_sink_request_rewind(s, (size_t) -1);
1554 case PA_SINK_MESSAGE_GET_MUTE:
1557 case PA_SINK_MESSAGE_SET_STATE:
1559 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1561 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1562 s->thread_info.rewind_nbytes = 0;
1563 s->thread_info.rewind_requested = FALSE;
1568 case PA_SINK_MESSAGE_DETACH:
1570 /* Detach all streams */
1571 pa_sink_detach_within_thread(s);
1574 case PA_SINK_MESSAGE_ATTACH:
1576 /* Reattach all streams */
1577 pa_sink_attach_within_thread(s);
1580 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1582 pa_usec_t *usec = userdata;
1583 *usec = pa_sink_get_requested_latency_within_thread(s);
1585 if (*usec == (pa_usec_t) -1)
1586 *usec = s->thread_info.max_latency;
1591 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1592 pa_usec_t *r = userdata;
1594 pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
1599 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1600 pa_usec_t *r = userdata;
1602 r[0] = s->thread_info.min_latency;
1603 r[1] = s->thread_info.max_latency;
1608 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1610 *((size_t*) userdata) = s->thread_info.max_rewind;
1613 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1615 *((size_t*) userdata) = s->thread_info.max_request;
1618 case PA_SINK_MESSAGE_SET_MAX_REWIND:
1620 pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
1623 case PA_SINK_MESSAGE_SET_MAX_REQUEST:
1625 pa_sink_set_max_request_within_thread(s, (size_t) offset);
1628 case PA_SINK_MESSAGE_GET_LATENCY:
1629 case PA_SINK_MESSAGE_MAX:
1636 /* Called from main thread */
1637 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1642 pa_core_assert_ref(c);
1644 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1647 if ((r = pa_sink_suspend(sink, suspend)) < 0)
1654 /* Called from main thread */
1655 void pa_sink_detach(pa_sink *s) {
1656 pa_sink_assert_ref(s);
1657 pa_assert(PA_SINK_IS_LINKED(s->state));
1659 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1662 /* Called from main thread */
1663 void pa_sink_attach(pa_sink *s) {
1664 pa_sink_assert_ref(s);
1665 pa_assert(PA_SINK_IS_LINKED(s->state));
1667 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1670 /* Called from IO thread */
1671 void pa_sink_detach_within_thread(pa_sink *s) {
1675 pa_sink_assert_ref(s);
1676 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1678 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1682 if (s->monitor_source)
1683 pa_source_detach_within_thread(s->monitor_source);
1686 /* Called from IO thread */
1687 void pa_sink_attach_within_thread(pa_sink *s) {
1691 pa_sink_assert_ref(s);
1692 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1694 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1698 if (s->monitor_source)
1699 pa_source_attach_within_thread(s->monitor_source);
1702 /* Called from IO thread */
1703 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1704 pa_sink_assert_ref(s);
1705 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1707 if (s->thread_info.state == PA_SINK_SUSPENDED)
1710 if (nbytes == (size_t) -1)
1711 nbytes = s->thread_info.max_rewind;
1713 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1715 if (s->thread_info.rewind_requested &&
1716 nbytes <= s->thread_info.rewind_nbytes)
1719 s->thread_info.rewind_nbytes = nbytes;
1720 s->thread_info.rewind_requested = TRUE;
1722 if (s->request_rewind)
1723 s->request_rewind(s);
1726 /* Called from IO thread */
1727 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1728 pa_usec_t result = (pa_usec_t) -1;
1731 pa_usec_t monitor_latency;
1733 pa_sink_assert_ref(s);
1735 if (s->thread_info.requested_latency_valid)
1736 return s->thread_info.requested_latency;
1738 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1740 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1741 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1742 result = i->thread_info.requested_sink_latency;
1744 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1746 if (monitor_latency != (pa_usec_t) -1 &&
1747 (result == (pa_usec_t) -1 || result > monitor_latency))
1748 result = monitor_latency;
1750 if (result != (pa_usec_t) -1) {
1751 if (result > s->thread_info.max_latency)
1752 result = s->thread_info.max_latency;
1754 if (result < s->thread_info.min_latency)
1755 result = s->thread_info.min_latency;
1758 s->thread_info.requested_latency = result;
1759 s->thread_info.requested_latency_valid = TRUE;
1764 /* Called from main thread */
1765 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1768 pa_sink_assert_ref(s);
1769 pa_assert(PA_SINK_IS_LINKED(s->state));
1771 if (s->state == PA_SINK_SUSPENDED)
1774 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1778 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1779 void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
1783 pa_sink_assert_ref(s);
1785 if (max_rewind == s->thread_info.max_rewind)
1788 s->thread_info.max_rewind = max_rewind;
1790 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1791 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1792 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1795 if (s->monitor_source)
1796 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
1799 /* Called from main thread */
1800 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1801 pa_sink_assert_ref(s);
1803 if (PA_SINK_IS_LINKED(s->state))
1804 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
1806 pa_sink_set_max_rewind_within_thread(s, max_rewind);
1809 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1810 void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
1813 pa_sink_assert_ref(s);
1815 if (max_request == s->thread_info.max_request)
1818 s->thread_info.max_request = max_request;
1820 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1823 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1824 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1828 /* Called from main thread */
1829 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1830 pa_sink_assert_ref(s);
1832 if (PA_SINK_IS_LINKED(s->state))
1833 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
1835 pa_sink_set_max_request_within_thread(s, max_request);
1838 /* Called from IO thread */
1839 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1843 pa_sink_assert_ref(s);
1845 s->thread_info.requested_latency_valid = FALSE;
1847 if (s->update_requested_latency)
1848 s->update_requested_latency(s);
1850 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1851 if (i->update_sink_requested_latency)
1852 i->update_sink_requested_latency(i);
1855 /* Called from main thread */
1856 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1857 pa_sink_assert_ref(s);
1859 /* min_latency == 0: no limit
1860 * min_latency == (size_t) -1: default limit
1861 * min_latency anything else: specified limit
1863 * Similar for max_latency */
1865 if (min_latency == (pa_usec_t) -1)
1866 min_latency = DEFAULT_MIN_LATENCY;
1868 if (min_latency < ABSOLUTE_MIN_LATENCY)
1869 min_latency = ABSOLUTE_MIN_LATENCY;
1871 if (max_latency == (pa_usec_t) -1)
1872 max_latency = min_latency;
1874 if (max_latency > ABSOLUTE_MAX_LATENCY || max_latency <= 0)
1875 max_latency = ABSOLUTE_MAX_LATENCY;
1877 pa_assert(min_latency <= max_latency);
1879 if (PA_SINK_IS_LINKED(s->state)) {
1885 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1887 s->thread_info.min_latency = min_latency;
1888 s->thread_info.max_latency = max_latency;
1890 s->monitor_source->thread_info.min_latency = min_latency;
1891 s->monitor_source->thread_info.max_latency = max_latency;
1893 s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
1897 /* Called from main thread */
1898 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1899 pa_sink_assert_ref(s);
1900 pa_assert(min_latency);
1901 pa_assert(max_latency);
1903 if (PA_SINK_IS_LINKED(s->state)) {
1904 pa_usec_t r[2] = { 0, 0 };
1906 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1908 *min_latency = r[0];
1909 *max_latency = r[1];
1911 *min_latency = s->thread_info.min_latency;
1912 *max_latency = s->thread_info.max_latency;
1916 /* Called from IO thread */
1917 void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1921 pa_sink_assert_ref(s);
1923 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
1924 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
1925 pa_assert(min_latency <= max_latency);
1927 s->thread_info.min_latency = min_latency;
1928 s->thread_info.max_latency = max_latency;
1930 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1931 if (i->update_sink_latency_range)
1932 i->update_sink_latency_range(i);
1934 pa_sink_invalidate_requested_latency(s);
1936 pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
1939 /* Called from main context */
1940 size_t pa_sink_get_max_rewind(pa_sink *s) {
1942 pa_sink_assert_ref(s);
1944 if (!PA_SINK_IS_LINKED(s->state))
1945 return s->thread_info.max_rewind;
1947 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1952 /* Called from main context */
1953 size_t pa_sink_get_max_request(pa_sink *s) {
1955 pa_sink_assert_ref(s);
1957 if (!PA_SINK_IS_LINKED(s->state))
1958 return s->thread_info.max_request;
1960 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1965 /* Called from main context */
1966 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
1967 const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
1971 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
1974 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
1976 if (pa_streq(ff, "microphone"))
1977 t = "audio-input-microphone";
1978 else if (pa_streq(ff, "webcam"))
1980 else if (pa_streq(ff, "computer"))
1982 else if (pa_streq(ff, "handset"))
1984 else if (pa_streq(ff, "portable"))
1985 t = "multimedia-player";
1986 else if (pa_streq(ff, "tv"))
1987 t = "video-display";
1991 if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
1992 if (pa_streq(c, "modem"))
1999 t = "audio-input-microphone";
2002 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
2003 if (strstr(profile, "analog"))
2005 else if (strstr(profile, "iec958"))
2007 else if (strstr(profile, "hdmi"))
2011 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
2013 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
2018 pa_bool_t pa_device_init_description(pa_proplist *p) {
2022 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
2025 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
2026 if (pa_streq(s, "internal")) {
2027 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
2031 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
2032 if (pa_streq(s, "modem")) {
2033 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
2037 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
2038 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);