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 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);
330 if (s->monitor_source)
331 pa_source_sync_suspend(s->monitor_source);
337 /* Called from main context */
338 void pa_sink_put(pa_sink* s) {
339 pa_sink_assert_ref(s);
341 pa_assert(s->state == PA_SINK_INIT);
343 /* The following fields must be initialized properly when calling _put() */
344 pa_assert(s->asyncmsgq);
345 pa_assert(s->rtpoll);
346 pa_assert(!s->thread_info.min_latency || !s->thread_info.max_latency ||
347 s->thread_info.min_latency <= s->thread_info.max_latency);
349 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL)) {
350 s->flags |= PA_SINK_DECIBEL_VOLUME;
352 s->thread_info.soft_volume = s->soft_volume;
353 s->thread_info.soft_muted = s->muted;
356 if (s->flags & PA_SINK_DECIBEL_VOLUME)
357 s->n_volume_steps = PA_VOLUME_NORM+1;
359 if (s->core->flat_volumes)
360 if (s->flags & PA_SINK_DECIBEL_VOLUME)
361 s->flags |= PA_SINK_FLAT_VOLUME;
363 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
365 pa_source_put(s->monitor_source);
367 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
368 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
371 /* Called from main context */
372 void pa_sink_unlink(pa_sink* s) {
374 pa_sink_input *i, *j = NULL;
378 /* Please note that pa_sink_unlink() does more than simply
379 * reversing pa_sink_put(). It also undoes the registrations
380 * already done in pa_sink_new()! */
382 /* All operations here shall be idempotent, i.e. pa_sink_unlink()
383 * may be called multiple times on the same sink without bad
386 linked = PA_SINK_IS_LINKED(s->state);
389 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
391 if (s->state != PA_SINK_UNLINKED)
392 pa_namereg_unregister(s->core, s->name);
393 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
396 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
398 while ((i = pa_idxset_first(s->inputs, NULL))) {
400 pa_sink_input_kill(i);
405 sink_set_state(s, PA_SINK_UNLINKED);
407 s->state = PA_SINK_UNLINKED;
411 if (s->monitor_source)
412 pa_source_unlink(s->monitor_source);
415 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
416 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
420 /* Called from main context */
421 static void sink_free(pa_object *o) {
422 pa_sink *s = PA_SINK(o);
426 pa_assert(pa_sink_refcnt(s) == 0);
428 if (PA_SINK_IS_LINKED(s->state))
431 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
433 if (s->monitor_source) {
434 pa_source_unref(s->monitor_source);
435 s->monitor_source = NULL;
438 pa_idxset_free(s->inputs, NULL, NULL);
440 while ((i = pa_hashmap_steal_first(s->thread_info.inputs)))
441 pa_sink_input_unref(i);
443 pa_hashmap_free(s->thread_info.inputs, NULL, NULL);
445 if (s->silence.memblock)
446 pa_memblock_unref(s->silence.memblock);
452 pa_proplist_free(s->proplist);
457 /* Called from main context */
458 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
459 pa_sink_assert_ref(s);
463 if (s->monitor_source)
464 pa_source_set_asyncmsgq(s->monitor_source, q);
467 /* Called from main context */
468 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
469 pa_sink_assert_ref(s);
472 if (s->monitor_source)
473 pa_source_set_rtpoll(s->monitor_source, p);
476 /* Called from main context */
477 int pa_sink_update_status(pa_sink*s) {
478 pa_sink_assert_ref(s);
479 pa_assert(PA_SINK_IS_LINKED(s->state));
481 if (s->state == PA_SINK_SUSPENDED)
484 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
487 /* Called from main context */
488 int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
489 pa_sink_assert_ref(s);
490 pa_assert(PA_SINK_IS_LINKED(s->state));
493 return sink_set_state(s, PA_SINK_SUSPENDED);
495 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
498 /* Called from main context */
499 pa_queue *pa_sink_move_all_start(pa_sink *s) {
501 pa_sink_input *i, *n;
504 pa_sink_assert_ref(s);
505 pa_assert(PA_SINK_IS_LINKED(s->state));
509 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
510 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
512 if (pa_sink_input_start_move(i) >= 0)
513 pa_queue_push(q, pa_sink_input_ref(i));
519 /* Called from main context */
520 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save) {
523 pa_sink_assert_ref(s);
524 pa_assert(PA_SINK_IS_LINKED(s->state));
527 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
528 if (pa_sink_input_finish_move(i, s, save) < 0)
529 pa_sink_input_kill(i);
531 pa_sink_input_unref(i);
534 pa_queue_free(q, NULL, NULL);
537 /* Called from main context */
538 void pa_sink_move_all_fail(pa_queue *q) {
542 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
543 if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_OK) {
544 pa_sink_input_kill(i);
545 pa_sink_input_unref(i);
549 pa_queue_free(q, NULL, NULL);
552 /* Called from IO thread context */
553 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
556 pa_sink_assert_ref(s);
557 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
559 /* If nobody requested this and this is actually no real rewind
560 * then we can short cut this */
561 if (!s->thread_info.rewind_requested && nbytes <= 0)
564 s->thread_info.rewind_nbytes = 0;
565 s->thread_info.rewind_requested = FALSE;
567 if (s->thread_info.state == PA_SINK_SUSPENDED)
571 pa_log_debug("Processing rewind...");
573 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
574 pa_sink_input_assert_ref(i);
575 pa_sink_input_process_rewind(i, nbytes);
579 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
580 pa_source_process_rewind(s->monitor_source, nbytes);
583 /* Called from IO thread context */
584 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
588 size_t mixlength = *length;
590 pa_sink_assert_ref(s);
593 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
594 pa_sink_input_assert_ref(i);
596 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
598 if (mixlength == 0 || info->chunk.length < mixlength)
599 mixlength = info->chunk.length;
601 if (pa_memblock_is_silence(info->chunk.memblock)) {
602 pa_memblock_unref(info->chunk.memblock);
606 info->userdata = pa_sink_input_ref(i);
608 pa_assert(info->chunk.memblock);
609 pa_assert(info->chunk.length > 0);
622 /* Called from IO thread context */
623 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
627 unsigned n_unreffed = 0;
629 pa_sink_assert_ref(s);
631 pa_assert(result->memblock);
632 pa_assert(result->length > 0);
634 /* We optimize for the case where the order of the inputs has not changed */
636 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
638 pa_mix_info* m = NULL;
640 pa_sink_input_assert_ref(i);
642 /* Let's try to find the matching entry info the pa_mix_info array */
643 for (j = 0; j < n; j ++) {
645 if (info[p].userdata == i) {
656 pa_sink_input_drop(i, result->length);
658 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
660 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
665 if (m && m->chunk.memblock) {
667 pa_memblock_ref(c.memblock);
668 pa_assert(result->length <= c.length);
669 c.length = result->length;
671 pa_memchunk_make_writable(&c, 0);
672 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
675 pa_memblock_ref(c.memblock);
676 pa_assert(result->length <= c.length);
677 c.length = result->length;
680 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
681 pa_source_output_assert_ref(o);
682 pa_assert(o->direct_on_input == i);
683 pa_source_post_direct(s->monitor_source, o, &c);
686 pa_memblock_unref(c.memblock);
691 if (m->chunk.memblock)
692 pa_memblock_unref(m->chunk.memblock);
693 pa_memchunk_reset(&m->chunk);
695 pa_sink_input_unref(m->userdata);
702 /* Now drop references to entries that are included in the
703 * pa_mix_info array but don't exist anymore */
705 if (n_unreffed < n) {
706 for (; n > 0; info++, n--) {
708 pa_sink_input_unref(info->userdata);
709 if (info->chunk.memblock)
710 pa_memblock_unref(info->chunk.memblock);
714 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
715 pa_source_post(s->monitor_source, result);
718 /* Called from IO thread context */
719 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
720 pa_mix_info info[MAX_MIX_CHANNELS];
722 size_t block_size_max;
724 pa_sink_assert_ref(s);
725 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
726 pa_assert(pa_frame_aligned(length, &s->sample_spec));
731 pa_assert(!s->thread_info.rewind_requested);
732 pa_assert(s->thread_info.rewind_nbytes == 0);
734 if (s->thread_info.state == PA_SINK_SUSPENDED) {
735 result->memblock = pa_memblock_ref(s->silence.memblock);
736 result->index = s->silence.index;
737 result->length = PA_MIN(s->silence.length, length);
742 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
744 block_size_max = pa_mempool_block_size_max(s->core->mempool);
745 if (length > block_size_max)
746 length = pa_frame_align(block_size_max, &s->sample_spec);
748 pa_assert(length > 0);
750 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
754 *result = s->silence;
755 pa_memblock_ref(result->memblock);
757 if (result->length > length)
758 result->length = length;
763 *result = info[0].chunk;
764 pa_memblock_ref(result->memblock);
766 if (result->length > length)
767 result->length = length;
769 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
771 if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
772 pa_memchunk_make_writable(result, 0);
773 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
774 pa_silence_memchunk(result, &s->sample_spec);
776 pa_volume_memchunk(result, &s->sample_spec, &volume);
780 result->memblock = pa_memblock_new(s->core->mempool, length);
782 ptr = pa_memblock_acquire(result->memblock);
783 result->length = pa_mix(info, n,
786 &s->thread_info.soft_volume,
787 s->thread_info.soft_muted);
788 pa_memblock_release(result->memblock);
793 inputs_drop(s, info, n, result);
798 /* Called from IO thread context */
799 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
800 pa_mix_info info[MAX_MIX_CHANNELS];
802 size_t length, block_size_max;
804 pa_sink_assert_ref(s);
805 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
807 pa_assert(target->memblock);
808 pa_assert(target->length > 0);
809 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
813 pa_assert(!s->thread_info.rewind_requested);
814 pa_assert(s->thread_info.rewind_nbytes == 0);
816 if (s->thread_info.state == PA_SINK_SUSPENDED) {
817 pa_silence_memchunk(target, &s->sample_spec);
821 length = target->length;
822 block_size_max = pa_mempool_block_size_max(s->core->mempool);
823 if (length > block_size_max)
824 length = pa_frame_align(block_size_max, &s->sample_spec);
826 pa_assert(length > 0);
828 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
831 if (target->length > length)
832 target->length = length;
834 pa_silence_memchunk(target, &s->sample_spec);
838 if (target->length > length)
839 target->length = length;
841 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
843 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
844 pa_silence_memchunk(target, &s->sample_spec);
848 vchunk = info[0].chunk;
849 pa_memblock_ref(vchunk.memblock);
851 if (vchunk.length > length)
852 vchunk.length = length;
854 if (!pa_cvolume_is_norm(&volume)) {
855 pa_memchunk_make_writable(&vchunk, 0);
856 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
859 pa_memchunk_memcpy(target, &vchunk);
860 pa_memblock_unref(vchunk.memblock);
866 ptr = pa_memblock_acquire(target->memblock);
868 target->length = pa_mix(info, n,
869 (uint8_t*) ptr + target->index, length,
871 &s->thread_info.soft_volume,
872 s->thread_info.soft_muted);
874 pa_memblock_release(target->memblock);
877 inputs_drop(s, info, n, target);
882 /* Called from IO thread context */
883 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
887 pa_sink_assert_ref(s);
888 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
890 pa_assert(target->memblock);
891 pa_assert(target->length > 0);
892 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
896 pa_assert(!s->thread_info.rewind_requested);
897 pa_assert(s->thread_info.rewind_nbytes == 0);
906 pa_sink_render_into(s, &chunk);
915 /* Called from IO thread context */
916 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
917 pa_sink_assert_ref(s);
918 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
919 pa_assert(length > 0);
920 pa_assert(pa_frame_aligned(length, &s->sample_spec));
923 pa_assert(!s->thread_info.rewind_requested);
924 pa_assert(s->thread_info.rewind_nbytes == 0);
926 /*** This needs optimization ***/
929 result->length = length;
930 result->memblock = pa_memblock_new(s->core->mempool, length);
932 pa_sink_render_into_full(s, result);
935 /* Called from main thread */
936 pa_usec_t pa_sink_get_latency(pa_sink *s) {
939 pa_sink_assert_ref(s);
940 pa_assert(PA_SINK_IS_LINKED(s->state));
942 /* The returned value is supposed to be in the time domain of the sound card! */
944 if (s->state == PA_SINK_SUSPENDED)
947 if (!(s->flags & PA_SINK_LATENCY))
950 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
955 /* Called from main thread */
956 void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
960 pa_sink_assert_ref(s);
961 pa_assert(new_volume);
962 pa_assert(PA_SINK_IS_LINKED(s->state));
963 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
965 /* This is called whenever a sink input volume changes and we
966 * might need to fix up the sink volume accordingly. Please note
967 * that we don't actually update the sinks volume here, we only
968 * return how it needs to be updated. The caller should then call
969 * pa_sink_set_flat_volume().*/
971 if (pa_idxset_isempty(s->inputs)) {
972 /* In the special case that we have no sink input we leave the
973 * volume unmodified. */
974 *new_volume = s->virtual_volume;
978 pa_cvolume_mute(new_volume, s->channel_map.channels);
980 /* First let's determine the new maximum volume of all inputs
981 * connected to this sink */
982 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
984 pa_cvolume remapped_volume;
986 remapped_volume = i->virtual_volume;
987 pa_cvolume_remap(&remapped_volume, &i->channel_map, &s->channel_map);
989 for (c = 0; c < new_volume->channels; c++)
990 if (remapped_volume.values[c] > new_volume->values[c])
991 new_volume->values[c] = remapped_volume.values[c];
994 /* Then, let's update the soft volumes of all inputs connected
996 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
997 pa_cvolume remapped_new_volume;
999 remapped_new_volume = *new_volume;
1000 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1001 pa_sw_cvolume_divide(&i->soft_volume, &i->virtual_volume, &remapped_new_volume);
1002 pa_sw_cvolume_multiply(&i->soft_volume, &i->soft_volume, &i->volume_factor);
1004 /* Hooks have the ability to play games with i->soft_volume */
1005 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], i);
1007 /* We don't issue PA_SINK_INPUT_MESSAGE_SET_VOLUME because
1008 * we want the update to have atomically with the sink
1009 * volume update, hence we do it within the
1010 * pa_sink_set_flat_volume() call below*/
1014 /* Called from main thread */
1015 void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
1019 pa_sink_assert_ref(s);
1020 pa_assert(old_volume);
1021 pa_assert(PA_SINK_IS_LINKED(s->state));
1022 pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
1024 /* This is called whenever the sink volume changes that is not
1025 * caused by a sink input volume change. We need to fix up the
1026 * sink input volumes accordingly */
1028 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1029 pa_cvolume remapped_old_volume, remapped_new_volume, fixed_volume;
1032 remapped_new_volume = s->virtual_volume;
1033 pa_cvolume_remap(&remapped_new_volume, &s->channel_map, &i->channel_map);
1035 remapped_old_volume = *old_volume;
1036 pa_cvolume_remap(&remapped_old_volume, &s->channel_map, &i->channel_map);
1038 for (c = 0; c < i->sample_spec.channels; c++)
1040 if (remapped_old_volume.values[c] == PA_VOLUME_MUTED)
1041 fixed_volume.values[c] = PA_VOLUME_MUTED;
1043 fixed_volume.values[c] = (pa_volume_t)
1044 ((uint64_t) i->virtual_volume.values[c] *
1045 (uint64_t) remapped_new_volume.values[c] /
1046 (uint64_t) remapped_old_volume.values[c]);
1048 fixed_volume.channels = i->virtual_volume.channels;
1050 if (!pa_cvolume_equal(&fixed_volume, &i->virtual_volume)) {
1051 i->virtual_volume = fixed_volume;
1053 /* The virtual volume changed, let's tell people so */
1054 pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
1059 /* Called from main thread */
1060 void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg) {
1061 pa_cvolume old_virtual_volume;
1062 pa_bool_t virtual_volume_changed;
1064 pa_sink_assert_ref(s);
1065 pa_assert(PA_SINK_IS_LINKED(s->state));
1067 pa_assert(pa_cvolume_valid(volume));
1068 pa_assert(pa_cvolume_compatible(volume, &s->sample_spec));
1070 old_virtual_volume = s->virtual_volume;
1071 s->virtual_volume = *volume;
1072 virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
1074 /* Propagate this volume change back to the inputs */
1075 if (virtual_volume_changed)
1076 if (propagate && (s->flags & PA_SINK_FLAT_VOLUME))
1077 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1079 if (s->set_volume) {
1080 /* If we have a function set_volume(), then we do not apply a
1081 * soft volume by default. However, set_volume() is apply one
1082 * to s->soft_volume */
1084 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
1088 /* If we have no function set_volume(), then the soft volume
1089 * becomes the virtual volume */
1090 s->soft_volume = s->virtual_volume;
1092 /* This tells the sink that soft and/or virtual volume changed */
1094 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1096 if (virtual_volume_changed)
1097 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1100 /* Called from main thread. Only to be called by sink implementor */
1101 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
1102 pa_sink_assert_ref(s);
1105 s->soft_volume = *volume;
1107 if (PA_SINK_IS_LINKED(s->state))
1108 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
1110 s->thread_info.soft_volume = *volume;
1113 /* Called from main thread */
1114 const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh) {
1115 pa_sink_assert_ref(s);
1117 if (s->refresh_volume || force_refresh) {
1118 struct pa_cvolume old_virtual_volume = s->virtual_volume;
1123 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
1125 if (!pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume)) {
1127 if (s->flags & PA_SINK_FLAT_VOLUME)
1128 pa_sink_propagate_flat_volume(s, &old_virtual_volume);
1130 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1134 return &s->virtual_volume;
1137 /* Called from main thread */
1138 void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
1139 pa_bool_t old_muted;
1141 pa_sink_assert_ref(s);
1142 pa_assert(PA_SINK_IS_LINKED(s->state));
1144 old_muted = s->muted;
1150 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
1152 if (old_muted != s->muted)
1153 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1156 /* Called from main thread */
1157 pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
1159 pa_sink_assert_ref(s);
1161 if (s->refresh_muted || force_refresh) {
1162 pa_bool_t old_muted = s->muted;
1167 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
1169 if (old_muted != s->muted)
1170 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1176 /* Called from main thread */
1177 pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
1179 pa_sink_assert_ref(s);
1182 pa_proplist_update(s->proplist, mode, p);
1184 if (PA_SINK_IS_LINKED(s->state)) {
1185 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1186 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1192 /* Called from main thread */
1193 void pa_sink_set_description(pa_sink *s, const char *description) {
1195 pa_sink_assert_ref(s);
1197 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
1200 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1202 if (old && description && !strcmp(old, description))
1206 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
1208 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
1210 if (s->monitor_source) {
1213 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
1214 pa_source_set_description(s->monitor_source, n);
1218 if (PA_SINK_IS_LINKED(s->state)) {
1219 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
1220 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
1224 /* Called from main thread */
1225 unsigned pa_sink_linked_by(pa_sink *s) {
1228 pa_sink_assert_ref(s);
1229 pa_assert(PA_SINK_IS_LINKED(s->state));
1231 ret = pa_idxset_size(s->inputs);
1233 /* We add in the number of streams connected to us here. Please
1234 * note the asymmmetry to pa_sink_used_by()! */
1236 if (s->monitor_source)
1237 ret += pa_source_linked_by(s->monitor_source);
1242 /* Called from main thread */
1243 unsigned pa_sink_used_by(pa_sink *s) {
1246 pa_sink_assert_ref(s);
1247 pa_assert(PA_SINK_IS_LINKED(s->state));
1249 ret = pa_idxset_size(s->inputs);
1250 pa_assert(ret >= s->n_corked);
1252 /* Streams connected to our monitor source do not matter for
1253 * pa_sink_used_by()!.*/
1255 return ret - s->n_corked;
1258 /* Called from main thread */
1259 unsigned pa_sink_check_suspend(pa_sink *s) {
1264 pa_sink_assert_ref(s);
1266 if (!PA_SINK_IS_LINKED(s->state))
1271 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
1272 pa_sink_input_state_t st;
1274 st = pa_sink_input_get_state(i);
1275 pa_assert(PA_SINK_INPUT_IS_LINKED(st));
1277 if (st == PA_SINK_INPUT_CORKED)
1280 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
1286 if (s->monitor_source)
1287 ret += pa_source_check_suspend(s->monitor_source);
1292 /* Called from the IO thread */
1293 static void sync_input_volumes_within_thread(pa_sink *s) {
1297 pa_sink_assert_ref(s);
1299 while ((i = PA_SINK_INPUT(pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))) {
1300 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
1303 i->thread_info.soft_volume = i->soft_volume;
1304 pa_sink_input_request_rewind(i, 0, TRUE, FALSE, FALSE);
1308 /* Called from IO thread, except when it is not */
1309 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
1310 pa_sink *s = PA_SINK(o);
1311 pa_sink_assert_ref(s);
1313 switch ((pa_sink_message_t) code) {
1315 case PA_SINK_MESSAGE_ADD_INPUT: {
1316 pa_sink_input *i = PA_SINK_INPUT(userdata);
1318 /* If you change anything here, make sure to change the
1319 * sink input handling a few lines down at
1320 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
1322 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1324 /* Since the caller sleeps in pa_sink_input_put(), we can
1325 * safely access data outside of thread_info even though
1328 if ((i->thread_info.sync_prev = i->sync_prev)) {
1329 pa_assert(i->sink == i->thread_info.sync_prev->sink);
1330 pa_assert(i->sync_prev->sync_next == i);
1331 i->thread_info.sync_prev->thread_info.sync_next = i;
1334 if ((i->thread_info.sync_next = i->sync_next)) {
1335 pa_assert(i->sink == i->thread_info.sync_next->sink);
1336 pa_assert(i->sync_next->sync_prev == i);
1337 i->thread_info.sync_next->thread_info.sync_prev = i;
1340 pa_assert(!i->thread_info.attached);
1341 i->thread_info.attached = TRUE;
1346 pa_sink_input_set_state_within_thread(i, i->state);
1348 /* The requested latency of the sink input needs to be
1349 * fixed up and then configured on the sink */
1351 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1352 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1354 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1355 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1357 /* We don't rewind here automatically. This is left to the
1358 * sink input implementor because some sink inputs need a
1359 * slow start, i.e. need some time to buffer client
1360 * samples before beginning streaming. */
1362 /* In flat volume mode we need to update the volume as
1364 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1367 case PA_SINK_MESSAGE_REMOVE_INPUT: {
1368 pa_sink_input *i = PA_SINK_INPUT(userdata);
1370 /* If you change anything here, make sure to change the
1371 * sink input handling a few lines down at
1372 * PA_SINK_MESSAGE_PREPAPRE_MOVE, too. */
1377 pa_sink_input_set_state_within_thread(i, i->state);
1379 pa_assert(i->thread_info.attached);
1380 i->thread_info.attached = FALSE;
1382 /* Since the caller sleeps in pa_sink_input_unlink(),
1383 * we can safely access data outside of thread_info even
1384 * though it is mutable */
1386 pa_assert(!i->sync_prev);
1387 pa_assert(!i->sync_next);
1389 if (i->thread_info.sync_prev) {
1390 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
1391 i->thread_info.sync_prev = NULL;
1394 if (i->thread_info.sync_next) {
1395 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
1396 i->thread_info.sync_next = NULL;
1399 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1400 pa_sink_input_unref(i);
1402 pa_sink_invalidate_requested_latency(s);
1403 pa_sink_request_rewind(s, (size_t) -1);
1405 /* In flat volume mode we need to update the volume as
1407 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1410 case PA_SINK_MESSAGE_START_MOVE: {
1411 pa_sink_input *i = PA_SINK_INPUT(userdata);
1413 /* We don't support moving synchronized streams. */
1414 pa_assert(!i->sync_prev);
1415 pa_assert(!i->sync_next);
1416 pa_assert(!i->thread_info.sync_next);
1417 pa_assert(!i->thread_info.sync_prev);
1419 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1421 size_t sink_nbytes, total_nbytes;
1423 /* Get the latency of the sink */
1424 if (!(s->flags & PA_SINK_LATENCY) ||
1425 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1428 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1429 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
1431 if (total_nbytes > 0) {
1432 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
1433 i->thread_info.rewrite_flush = TRUE;
1434 pa_sink_input_process_rewind(i, sink_nbytes);
1441 pa_assert(i->thread_info.attached);
1442 i->thread_info.attached = FALSE;
1444 /* Let's remove the sink input ...*/
1445 if (pa_hashmap_remove(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index)))
1446 pa_sink_input_unref(i);
1448 pa_sink_invalidate_requested_latency(s);
1450 pa_log_debug("Requesting rewind due to started move");
1451 pa_sink_request_rewind(s, (size_t) -1);
1453 /* In flat volume mode we need to update the volume as
1455 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1458 case PA_SINK_MESSAGE_FINISH_MOVE: {
1459 pa_sink_input *i = PA_SINK_INPUT(userdata);
1461 /* We don't support moving synchronized streams. */
1462 pa_assert(!i->sync_prev);
1463 pa_assert(!i->sync_next);
1464 pa_assert(!i->thread_info.sync_next);
1465 pa_assert(!i->thread_info.sync_prev);
1467 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
1469 pa_assert(!i->thread_info.attached);
1470 i->thread_info.attached = TRUE;
1475 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
1476 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
1478 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1479 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1481 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
1485 /* Get the latency of the sink */
1486 if (!(s->flags & PA_SINK_LATENCY) ||
1487 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
1490 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
1493 pa_sink_input_drop(i, nbytes);
1495 pa_log_debug("Requesting rewind due to finished move");
1496 pa_sink_request_rewind(s, nbytes);
1499 /* In flat volume mode we need to update the volume as
1501 return o->process_msg(o, PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL);
1504 case PA_SINK_MESSAGE_SET_VOLUME:
1506 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
1507 s->thread_info.soft_volume = s->soft_volume;
1508 pa_sink_request_rewind(s, (size_t) -1);
1511 if (s->flags & PA_SINK_FLAT_VOLUME)
1512 sync_input_volumes_within_thread(s);
1516 case PA_SINK_MESSAGE_GET_VOLUME:
1519 case PA_SINK_MESSAGE_SET_MUTE:
1521 if (s->thread_info.soft_muted != s->muted) {
1522 s->thread_info.soft_muted = s->muted;
1523 pa_sink_request_rewind(s, (size_t) -1);
1528 case PA_SINK_MESSAGE_GET_MUTE:
1531 case PA_SINK_MESSAGE_SET_STATE:
1533 s->thread_info.state = PA_PTR_TO_UINT(userdata);
1535 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1536 s->thread_info.rewind_nbytes = 0;
1537 s->thread_info.rewind_requested = FALSE;
1542 case PA_SINK_MESSAGE_DETACH:
1544 /* Detach all streams */
1545 pa_sink_detach_within_thread(s);
1548 case PA_SINK_MESSAGE_ATTACH:
1550 /* Reattach all streams */
1551 pa_sink_attach_within_thread(s);
1554 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
1556 pa_usec_t *usec = userdata;
1557 *usec = pa_sink_get_requested_latency_within_thread(s);
1559 if (*usec == (pa_usec_t) -1)
1560 *usec = s->thread_info.max_latency;
1565 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
1566 pa_usec_t *r = userdata;
1568 pa_sink_update_latency_range(s, r[0], r[1]);
1573 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
1574 pa_usec_t *r = userdata;
1576 r[0] = s->thread_info.min_latency;
1577 r[1] = s->thread_info.max_latency;
1582 case PA_SINK_MESSAGE_GET_MAX_REWIND:
1584 *((size_t*) userdata) = s->thread_info.max_rewind;
1587 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
1589 *((size_t*) userdata) = s->thread_info.max_request;
1592 case PA_SINK_MESSAGE_GET_LATENCY:
1593 case PA_SINK_MESSAGE_MAX:
1600 /* Called from main thread */
1601 int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
1606 pa_core_assert_ref(c);
1608 for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
1611 if ((r = pa_sink_suspend(sink, suspend)) < 0)
1618 /* Called from main thread */
1619 void pa_sink_detach(pa_sink *s) {
1620 pa_sink_assert_ref(s);
1621 pa_assert(PA_SINK_IS_LINKED(s->state));
1623 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_DETACH, NULL, 0, NULL) == 0);
1626 /* Called from main thread */
1627 void pa_sink_attach(pa_sink *s) {
1628 pa_sink_assert_ref(s);
1629 pa_assert(PA_SINK_IS_LINKED(s->state));
1631 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_ATTACH, NULL, 0, NULL) == 0);
1634 /* Called from IO thread */
1635 void pa_sink_detach_within_thread(pa_sink *s) {
1639 pa_sink_assert_ref(s);
1640 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1642 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1646 if (s->monitor_source)
1647 pa_source_detach_within_thread(s->monitor_source);
1650 /* Called from IO thread */
1651 void pa_sink_attach_within_thread(pa_sink *s) {
1655 pa_sink_assert_ref(s);
1656 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1658 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1662 if (s->monitor_source)
1663 pa_source_attach_within_thread(s->monitor_source);
1666 /* Called from IO thread */
1667 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
1668 pa_sink_assert_ref(s);
1669 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1671 if (s->thread_info.state == PA_SINK_SUSPENDED)
1674 if (nbytes == (size_t) -1)
1675 nbytes = s->thread_info.max_rewind;
1677 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
1679 if (s->thread_info.rewind_requested &&
1680 nbytes <= s->thread_info.rewind_nbytes)
1683 s->thread_info.rewind_nbytes = nbytes;
1684 s->thread_info.rewind_requested = TRUE;
1686 if (s->request_rewind)
1687 s->request_rewind(s);
1690 /* Called from IO thread */
1691 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
1692 pa_usec_t result = (pa_usec_t) -1;
1695 pa_usec_t monitor_latency;
1697 pa_sink_assert_ref(s);
1699 if (s->thread_info.requested_latency_valid)
1700 return s->thread_info.requested_latency;
1702 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1704 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
1705 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
1706 result = i->thread_info.requested_sink_latency;
1708 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
1710 if (monitor_latency != (pa_usec_t) -1 &&
1711 (result == (pa_usec_t) -1 || result > monitor_latency))
1712 result = monitor_latency;
1714 if (result != (pa_usec_t) -1) {
1715 if (s->thread_info.max_latency > 0 && result > s->thread_info.max_latency)
1716 result = s->thread_info.max_latency;
1718 if (s->thread_info.min_latency > 0 && result < s->thread_info.min_latency)
1719 result = s->thread_info.min_latency;
1722 s->thread_info.requested_latency = result;
1723 s->thread_info.requested_latency_valid = TRUE;
1728 /* Called from main thread */
1729 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
1732 pa_sink_assert_ref(s);
1733 pa_assert(PA_SINK_IS_LINKED(s->state));
1735 if (s->state == PA_SINK_SUSPENDED)
1738 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
1742 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1743 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
1747 pa_sink_assert_ref(s);
1749 if (max_rewind == s->thread_info.max_rewind)
1752 s->thread_info.max_rewind = max_rewind;
1754 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1755 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1756 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
1759 if (s->monitor_source)
1760 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
1763 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
1764 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
1767 pa_sink_assert_ref(s);
1769 if (max_request == s->thread_info.max_request)
1772 s->thread_info.max_request = max_request;
1774 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
1777 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1778 pa_sink_input_update_max_request(i, s->thread_info.max_request);
1782 /* Called from IO thread */
1783 void pa_sink_invalidate_requested_latency(pa_sink *s) {
1787 pa_sink_assert_ref(s);
1789 s->thread_info.requested_latency_valid = FALSE;
1791 if (s->update_requested_latency)
1792 s->update_requested_latency(s);
1794 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1795 if (i->update_sink_requested_latency)
1796 i->update_sink_requested_latency(i);
1799 /* Called from main thread */
1800 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1801 pa_sink_assert_ref(s);
1803 /* min_latency == 0: no limit
1804 * min_latency == (size_t) -1: default limit
1805 * min_latency anything else: specified limit
1807 * Similar for max_latency */
1809 if (min_latency == (pa_usec_t) -1)
1810 min_latency = DEFAULT_MIN_LATENCY;
1812 if (max_latency == (pa_usec_t) -1)
1813 max_latency = min_latency;
1815 pa_assert(!min_latency || !max_latency ||
1816 min_latency <= max_latency);
1818 if (PA_SINK_IS_LINKED(s->state)) {
1824 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
1826 s->thread_info.min_latency = min_latency;
1827 s->thread_info.max_latency = max_latency;
1829 s->monitor_source->thread_info.min_latency = min_latency;
1830 s->monitor_source->thread_info.max_latency = max_latency;
1832 s->thread_info.requested_latency_valid = s->monitor_source->thread_info.requested_latency_valid = FALSE;
1836 /* Called from main thread */
1837 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
1838 pa_sink_assert_ref(s);
1839 pa_assert(min_latency);
1840 pa_assert(max_latency);
1842 if (PA_SINK_IS_LINKED(s->state)) {
1843 pa_usec_t r[2] = { 0, 0 };
1845 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
1847 *min_latency = r[0];
1848 *max_latency = r[1];
1850 *min_latency = s->thread_info.min_latency;
1851 *max_latency = s->thread_info.max_latency;
1855 /* Called from IO thread */
1856 void pa_sink_update_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
1860 pa_sink_assert_ref(s);
1862 pa_assert(!min_latency || !max_latency ||
1863 min_latency <= max_latency);
1865 s->thread_info.min_latency = min_latency;
1866 s->thread_info.max_latency = max_latency;
1868 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
1869 if (i->update_sink_latency_range)
1870 i->update_sink_latency_range(i);
1872 pa_sink_invalidate_requested_latency(s);
1874 pa_source_update_latency_range(s->monitor_source, min_latency, max_latency);
1877 /* Called from main context */
1878 size_t pa_sink_get_max_rewind(pa_sink *s) {
1880 pa_sink_assert_ref(s);
1882 if (!PA_SINK_IS_LINKED(s->state))
1883 return s->thread_info.max_rewind;
1885 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
1890 /* Called from main context */
1891 size_t pa_sink_get_max_request(pa_sink *s) {
1893 pa_sink_assert_ref(s);
1895 if (!PA_SINK_IS_LINKED(s->state))
1896 return s->thread_info.max_request;
1898 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
1903 /* Called from main context */
1904 pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
1905 const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
1909 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
1912 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
1914 if (pa_streq(ff, "microphone"))
1915 t = "audio-input-microphone";
1916 else if (pa_streq(ff, "webcam"))
1918 else if (pa_streq(ff, "computer"))
1920 else if (pa_streq(ff, "handset"))
1922 else if (pa_streq(ff, "portable"))
1923 t = "multimedia-player";
1924 else if (pa_streq(ff, "tv"))
1925 t = "video-display";
1929 if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
1930 if (pa_streq(c, "modem"))
1937 t = "audio-input-microphone";
1940 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
1941 if (strstr(profile, "analog"))
1943 else if (strstr(profile, "iec958"))
1945 else if (strstr(profile, "hdmi"))
1949 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
1951 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
1956 pa_bool_t pa_device_init_description(pa_proplist *p) {
1960 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
1963 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
1964 if (pa_streq(s, "internal")) {
1965 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
1969 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
1970 if (pa_streq(s, "modem")) {
1971 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
1975 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
1976 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);