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, see <http://www.gnu.org/licenses/>.
32 #include <pulse/introspect.h>
33 #include <pulse/format.h>
34 #include <pulse/utf8.h>
35 #include <pulse/xmalloc.h>
36 #include <pulse/timeval.h>
37 #include <pulse/util.h>
38 #include <pulse/rtclock.h>
39 #include <pulse/internal.h>
41 #include <pulsecore/i18n.h>
42 #include <pulsecore/sink-input.h>
43 #include <pulsecore/namereg.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/sample-util.h>
46 #include <pulsecore/mix.h>
47 #include <pulsecore/core-subscribe.h>
48 #include <pulsecore/log.h>
49 #include <pulsecore/macro.h>
50 #include <pulsecore/play-memblockq.h>
51 #include <pulsecore/flist.h>
55 #define MAX_MIX_CHANNELS 32
56 #define MIX_BUFFER_LENGTH (pa_page_size())
57 #define ABSOLUTE_MIN_LATENCY (500)
58 #define ABSOLUTE_MAX_LATENCY (10*PA_USEC_PER_SEC)
59 #define DEFAULT_FIXED_LATENCY (250*PA_USEC_PER_MSEC)
61 PA_DEFINE_PUBLIC_CLASS(pa_sink, pa_msgobject);
63 struct pa_sink_volume_change {
67 PA_LLIST_FIELDS(pa_sink_volume_change);
70 struct sink_message_set_port {
75 static void sink_free(pa_object *s);
77 static void pa_sink_volume_change_push(pa_sink *s);
78 static void pa_sink_volume_change_flush(pa_sink *s);
79 static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes);
82 static void pa_sink_write_pcm_dump(pa_sink *s, pa_memchunk *chunk)
84 char *dump_time = NULL, *dump_path_surfix = NULL;
85 const char *s_device_api_str, *card_name_str, *device_idx_str;
90 /* open file for dump pcm */
91 if (s->core->pcm_dump & PA_PCM_DUMP_PA_SINK && !s->pcm_dump_fp && s->state == PA_SINK_RUNNING) {
92 pa_gettimeofday(&now);
93 localtime_r(&now.tv_sec, &tm);
94 memset(&datetime[0], 0x00, sizeof(datetime));
95 strftime(&datetime[0], sizeof(datetime), "%H%M%S", &tm);
96 dump_time = pa_sprintf_malloc("%s.%03ld", &datetime[0], now.tv_usec / 1000);
98 if ((s_device_api_str = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_API))) {
99 if (pa_streq(s_device_api_str, "alsa")) {
100 card_name_str = pa_proplist_gets(s->proplist, "alsa.card_name");
101 device_idx_str = pa_proplist_gets(s->proplist, "alsa.device");
102 dump_path_surfix = pa_sprintf_malloc("%s.%s", pa_strnull(card_name_str), pa_strnull(device_idx_str));
104 dump_path_surfix = pa_sprintf_malloc("%s", s_device_api_str);
107 dump_path_surfix = pa_sprintf_malloc("%s", s->name);
110 s->dump_path = pa_sprintf_malloc("%s_%s_pa-sink%d-%s_%dch_%d.raw", PA_PCM_DUMP_PATH_PREFIX, pa_strempty(dump_time),
111 s->index, pa_strempty(dump_path_surfix), s->sample_spec.channels, s->sample_spec.rate);
113 s->pcm_dump_fp = fopen(s->dump_path, "w");
115 pa_log_warn("%s open failed", s->dump_path);
117 pa_log_info("%s opened", s->dump_path);
120 pa_xfree(dump_path_surfix);
121 /* close file for dump pcm when config is changed */
122 } else if (~s->core->pcm_dump & PA_PCM_DUMP_PA_SINK && s->pcm_dump_fp) {
123 fclose(s->pcm_dump_fp);
124 pa_log_info("%s closed", s->dump_path);
125 pa_xfree(s->dump_path);
126 s->pcm_dump_fp = NULL;
130 if (s->pcm_dump_fp) {
133 ptr = pa_memblock_acquire(chunk->memblock);
135 fwrite((uint8_t *)ptr + chunk->index, 1, chunk->length, s->pcm_dump_fp);
137 pa_log_warn("pa_memblock_acquire is failed. ptr is NULL");
139 pa_memblock_release(chunk->memblock);
144 pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data) {
148 data->proplist = pa_proplist_new();
149 data->ports = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL, (pa_free_cb_t) pa_device_port_unref);
154 void pa_sink_new_data_set_name(pa_sink_new_data *data, const char *name) {
157 pa_xfree(data->name);
158 data->name = pa_xstrdup(name);
161 void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_spec *spec) {
164 if ((data->sample_spec_is_set = !!spec))
165 data->sample_spec = *spec;
168 void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map) {
171 if ((data->channel_map_is_set = !!map))
172 data->channel_map = *map;
175 void pa_sink_new_data_set_alternate_sample_rate(pa_sink_new_data *data, const uint32_t alternate_sample_rate) {
178 data->alternate_sample_rate_is_set = true;
179 data->alternate_sample_rate = alternate_sample_rate;
182 void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume) {
185 if ((data->volume_is_set = !!volume))
186 data->volume = *volume;
189 void pa_sink_new_data_set_muted(pa_sink_new_data *data, bool mute) {
192 data->muted_is_set = true;
196 void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port) {
199 pa_xfree(data->active_port);
200 data->active_port = pa_xstrdup(port);
203 void pa_sink_new_data_done(pa_sink_new_data *data) {
206 pa_proplist_free(data->proplist);
209 pa_hashmap_free(data->ports);
211 pa_xfree(data->name);
212 pa_xfree(data->active_port);
215 /* Called from main context */
216 static void reset_callbacks(pa_sink *s) {
220 s->get_volume = NULL;
221 s->set_volume = NULL;
222 s->write_volume = NULL;
225 s->request_rewind = NULL;
226 s->update_requested_latency = NULL;
228 s->get_formats = NULL;
229 s->set_formats = NULL;
230 s->update_rate = NULL;
233 /* Called from main context */
234 pa_sink* pa_sink_new(
236 pa_sink_new_data *data,
237 pa_sink_flags_t flags) {
241 char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
242 pa_source_new_data source_data;
248 pa_assert(data->name);
249 pa_assert_ctl_context();
251 s = pa_msgobject_new(pa_sink);
253 if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
254 pa_log_debug("Failed to register name %s.", data->name);
259 pa_sink_new_data_set_name(data, name);
261 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_NEW], data) < 0) {
263 pa_namereg_unregister(core, name);
267 /* FIXME, need to free s here on failure */
269 pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
270 pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
272 pa_return_null_if_fail(data->sample_spec_is_set && pa_sample_spec_valid(&data->sample_spec));
274 if (!data->channel_map_is_set)
275 pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT));
277 pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map));
278 pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels);
280 /* FIXME: There should probably be a general function for checking whether
281 * the sink volume is allowed to be set, like there is for sink inputs. */
282 pa_assert(!data->volume_is_set || !(flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
284 if (!data->volume_is_set) {
285 pa_cvolume_reset(&data->volume, data->sample_spec.channels);
286 data->save_volume = false;
289 pa_return_null_if_fail(pa_cvolume_valid(&data->volume));
290 pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec));
292 if (!data->muted_is_set)
296 pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->card->proplist);
298 pa_device_init_description(data->proplist, data->card);
299 pa_device_init_icon(data->proplist, true);
300 pa_device_init_intended_roles(data->proplist);
302 if (!data->active_port) {
303 pa_device_port *p = pa_device_port_find_best(data->ports);
305 pa_sink_new_data_set_port(data, p->name);
308 if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
310 pa_namereg_unregister(core, name);
314 s->parent.parent.free = sink_free;
315 s->parent.process_msg = pa_sink_process_msg;
318 s->state = PA_SINK_INIT;
321 s->suspend_cause = data->suspend_cause;
322 pa_sink_set_mixer_dirty(s, false);
323 s->name = pa_xstrdup(name);
324 s->proplist = pa_proplist_copy(data->proplist);
325 s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
326 s->module = data->module;
327 s->card = data->card;
329 s->priority = pa_device_init_priority(s->proplist);
331 s->sample_spec = data->sample_spec;
332 s->channel_map = data->channel_map;
333 s->default_sample_rate = s->sample_spec.rate;
335 if (data->alternate_sample_rate_is_set)
336 s->alternate_sample_rate = data->alternate_sample_rate;
338 s->alternate_sample_rate = s->core->alternate_sample_rate;
340 if (s->sample_spec.rate == s->alternate_sample_rate) {
341 pa_log_warn("Default and alternate sample rates are the same.");
342 s->alternate_sample_rate = 0;
345 s->inputs = pa_idxset_new(NULL, NULL);
347 s->input_to_master = NULL;
349 s->reference_volume = s->real_volume = data->volume;
350 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
351 s->base_volume = PA_VOLUME_NORM;
352 s->n_volume_steps = PA_VOLUME_NORM+1;
353 s->muted = data->muted;
354 s->refresh_volume = s->refresh_muted = false;
361 /* As a minor optimization we just steal the list instead of
363 s->ports = data->ports;
366 s->active_port = NULL;
367 s->save_port = false;
369 if (data->active_port)
370 if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
371 s->save_port = data->save_port;
373 /* Hopefully the active port has already been assigned in the previous call
374 to pa_device_port_find_best, but better safe than sorry */
376 s->active_port = pa_device_port_find_best(s->ports);
379 s->port_latency_offset = s->active_port->latency_offset;
381 s->port_latency_offset = 0;
383 s->save_volume = data->save_volume;
384 s->save_muted = data->save_muted;
385 #ifdef TIZEN_PCM_DUMP
386 s->pcm_dump_fp = NULL;
390 pa_silence_memchunk_get(
391 &core->silence_cache,
397 s->thread_info.rtpoll = NULL;
398 s->thread_info.inputs = pa_hashmap_new_full(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func, NULL,
399 (pa_free_cb_t) pa_sink_input_unref);
400 s->thread_info.soft_volume = s->soft_volume;
401 s->thread_info.soft_muted = s->muted;
402 s->thread_info.state = s->state;
403 s->thread_info.rewind_nbytes = 0;
404 s->thread_info.rewind_requested = false;
405 s->thread_info.max_rewind = 0;
406 s->thread_info.max_request = 0;
407 s->thread_info.requested_latency_valid = false;
408 s->thread_info.requested_latency = 0;
409 s->thread_info.min_latency = ABSOLUTE_MIN_LATENCY;
410 s->thread_info.max_latency = ABSOLUTE_MAX_LATENCY;
411 s->thread_info.fixed_latency = flags & PA_SINK_DYNAMIC_LATENCY ? 0 : DEFAULT_FIXED_LATENCY;
413 PA_LLIST_HEAD_INIT(pa_sink_volume_change, s->thread_info.volume_changes);
414 s->thread_info.volume_changes_tail = NULL;
415 pa_sw_cvolume_divide(&s->thread_info.current_hw_volume, &s->real_volume, &s->soft_volume);
416 s->thread_info.volume_change_safety_margin = core->deferred_volume_safety_margin_usec;
417 s->thread_info.volume_change_extra_delay = core->deferred_volume_extra_delay_usec;
418 s->thread_info.port_latency_offset = s->port_latency_offset;
420 /* FIXME: This should probably be moved to pa_sink_put() */
421 pa_assert_se(pa_idxset_put(core->sinks, s, &s->index) >= 0);
424 pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
426 pt = pa_proplist_to_string_sep(s->proplist, "\n ");
427 pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
430 pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
431 pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
435 pa_source_new_data_init(&source_data);
436 pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
437 pa_source_new_data_set_channel_map(&source_data, &s->channel_map);
438 pa_source_new_data_set_alternate_sample_rate(&source_data, s->alternate_sample_rate);
439 source_data.name = pa_sprintf_malloc("%s.monitor", name);
440 source_data.driver = data->driver;
441 source_data.module = data->module;
442 source_data.card = data->card;
444 dn = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
445 pa_proplist_setf(source_data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Monitor of %s", dn ? dn : s->name);
446 pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_CLASS, "monitor");
448 s->monitor_source = pa_source_new(core, &source_data,
449 ((flags & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
450 ((flags & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0));
452 pa_source_new_data_done(&source_data);
454 if (!s->monitor_source) {
460 s->monitor_source->monitor_of = s;
462 pa_source_set_latency_range(s->monitor_source, s->thread_info.min_latency, s->thread_info.max_latency);
463 pa_source_set_fixed_latency(s->monitor_source, s->thread_info.fixed_latency);
464 pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
469 /* Called from main context */
470 static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
473 pa_sink_state_t original_state;
476 pa_assert_ctl_context();
478 if (s->state == state)
481 original_state = s->state;
484 (original_state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) ||
485 (PA_SINK_IS_OPENED(original_state) && state == PA_SINK_SUSPENDED);
488 if ((ret = s->set_state(s, state)) < 0)
492 if ((ret = pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL)) < 0) {
495 s->set_state(s, original_state);
501 #ifdef TIZEN_PCM_DUMP
502 /* close file for dump pcm */
503 if (s->pcm_dump_fp && (s->core->pcm_dump_option & PA_PCM_DUMP_OPTION_SEPARATED) &&
504 state == PA_SINK_IDLE && original_state == PA_SINK_RUNNING) {
505 fclose(s->pcm_dump_fp);
506 pa_log_info("%s closed", s->dump_path);
507 pa_xfree(s->dump_path);
508 s->pcm_dump_fp = NULL;
512 if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the appropriate events */
513 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
514 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
517 if (suspend_change) {
521 /* We're suspending or resuming, tell everyone about it */
523 PA_IDXSET_FOREACH(i, s->inputs, idx)
524 if (s->state == PA_SINK_SUSPENDED &&
525 (i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND))
526 pa_sink_input_kill(i);
528 i->suspend(i, state == PA_SINK_SUSPENDED);
530 if (s->monitor_source)
531 pa_source_sync_suspend(s->monitor_source);
537 void pa_sink_set_get_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
543 void pa_sink_set_set_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
544 pa_sink_flags_t flags;
547 pa_assert(!s->write_volume || cb);
551 /* Save the current flags so we can tell if they've changed */
555 /* The sink implementor is responsible for setting decibel volume support */
556 s->flags |= PA_SINK_HW_VOLUME_CTRL;
558 s->flags &= ~PA_SINK_HW_VOLUME_CTRL;
559 /* See note below in pa_sink_put() about volume sharing and decibel volumes */
560 pa_sink_enable_decibel_volume(s, !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
563 /* If the flags have changed after init, let any clients know via a change event */
564 if (s->state != PA_SINK_INIT && flags != s->flags)
565 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
568 void pa_sink_set_write_volume_callback(pa_sink *s, pa_sink_cb_t cb) {
569 pa_sink_flags_t flags;
572 pa_assert(!cb || s->set_volume);
574 s->write_volume = cb;
576 /* Save the current flags so we can tell if they've changed */
580 s->flags |= PA_SINK_DEFERRED_VOLUME;
582 s->flags &= ~PA_SINK_DEFERRED_VOLUME;
584 /* If the flags have changed after init, let any clients know via a change event */
585 if (s->state != PA_SINK_INIT && flags != s->flags)
586 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
589 void pa_sink_set_get_mute_callback(pa_sink *s, pa_sink_get_mute_cb_t cb) {
595 void pa_sink_set_set_mute_callback(pa_sink *s, pa_sink_cb_t cb) {
596 pa_sink_flags_t flags;
602 /* Save the current flags so we can tell if they've changed */
606 s->flags |= PA_SINK_HW_MUTE_CTRL;
608 s->flags &= ~PA_SINK_HW_MUTE_CTRL;
610 /* If the flags have changed after init, let any clients know via a change event */
611 if (s->state != PA_SINK_INIT && flags != s->flags)
612 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
615 static void enable_flat_volume(pa_sink *s, bool enable) {
616 pa_sink_flags_t flags;
620 /* Always follow the overall user preference here */
621 enable = enable && s->core->flat_volumes;
623 /* Save the current flags so we can tell if they've changed */
627 s->flags |= PA_SINK_FLAT_VOLUME;
629 s->flags &= ~PA_SINK_FLAT_VOLUME;
631 /* If the flags have changed after init, let any clients know via a change event */
632 if (s->state != PA_SINK_INIT && flags != s->flags)
633 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
636 void pa_sink_enable_decibel_volume(pa_sink *s, bool enable) {
637 pa_sink_flags_t flags;
641 /* Save the current flags so we can tell if they've changed */
645 s->flags |= PA_SINK_DECIBEL_VOLUME;
646 enable_flat_volume(s, true);
648 s->flags &= ~PA_SINK_DECIBEL_VOLUME;
649 enable_flat_volume(s, false);
652 /* If the flags have changed after init, let any clients know via a change event */
653 if (s->state != PA_SINK_INIT && flags != s->flags)
654 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
657 /* Called from main context */
658 void pa_sink_put(pa_sink* s) {
659 pa_sink_assert_ref(s);
660 pa_assert_ctl_context();
662 pa_assert(s->state == PA_SINK_INIT);
663 pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || pa_sink_is_filter(s));
665 /* The following fields must be initialized properly when calling _put() */
666 pa_assert(s->asyncmsgq);
667 pa_assert(s->thread_info.min_latency <= s->thread_info.max_latency);
669 /* Generally, flags should be initialized via pa_sink_new(). As a
670 * special exception we allow some volume related flags to be set
671 * between _new() and _put() by the callback setter functions above.
673 * Thus we implement a couple safeguards here which ensure the above
674 * setters were used (or at least the implementor made manual changes
675 * in a compatible way).
677 * Note: All of these flags set here can change over the life time
679 pa_assert(!(s->flags & PA_SINK_HW_VOLUME_CTRL) || s->set_volume);
680 pa_assert(!(s->flags & PA_SINK_DEFERRED_VOLUME) || s->write_volume);
681 pa_assert(!(s->flags & PA_SINK_HW_MUTE_CTRL) || s->set_mute);
683 /* XXX: Currently decibel volume is disabled for all sinks that use volume
684 * sharing. When the master sink supports decibel volume, it would be good
685 * to have the flag also in the filter sink, but currently we don't do that
686 * so that the flags of the filter sink never change when it's moved from
687 * a master sink to another. One solution for this problem would be to
688 * remove user-visible volume altogether from filter sinks when volume
689 * sharing is used, but the current approach was easier to implement... */
690 /* We always support decibel volumes in software, otherwise we leave it to
691 * the sink implementor to set this flag as needed.
693 * Note: This flag can also change over the life time of the sink. */
694 if (!(s->flags & PA_SINK_HW_VOLUME_CTRL) && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
695 pa_sink_enable_decibel_volume(s, true);
696 s->soft_volume = s->reference_volume;
699 /* If the sink implementor support DB volumes by itself, we should always
700 * try and enable flat volumes too */
701 if ((s->flags & PA_SINK_DECIBEL_VOLUME))
702 enable_flat_volume(s, true);
704 if (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) {
705 pa_sink *root_sink = pa_sink_get_master(s);
707 pa_assert(root_sink);
709 s->reference_volume = root_sink->reference_volume;
710 pa_cvolume_remap(&s->reference_volume, &root_sink->channel_map, &s->channel_map);
712 s->real_volume = root_sink->real_volume;
713 pa_cvolume_remap(&s->real_volume, &root_sink->channel_map, &s->channel_map);
715 /* We assume that if the sink implementor changed the default
716 * volume he did so in real_volume, because that is the usual
717 * place where he is supposed to place his changes. */
718 s->reference_volume = s->real_volume;
720 s->thread_info.soft_volume = s->soft_volume;
721 s->thread_info.soft_muted = s->muted;
722 pa_sw_cvolume_divide(&s->thread_info.current_hw_volume, &s->real_volume, &s->soft_volume);
724 pa_assert((s->flags & PA_SINK_HW_VOLUME_CTRL)
725 || (s->base_volume == PA_VOLUME_NORM
726 && ((s->flags & PA_SINK_DECIBEL_VOLUME || (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)))));
727 pa_assert(!(s->flags & PA_SINK_DECIBEL_VOLUME) || s->n_volume_steps == PA_VOLUME_NORM+1);
728 pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->thread_info.fixed_latency == 0));
729 pa_assert(!(s->flags & PA_SINK_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_LATENCY));
730 pa_assert(!(s->flags & PA_SINK_DYNAMIC_LATENCY) == !(s->monitor_source->flags & PA_SOURCE_DYNAMIC_LATENCY));
732 pa_assert(s->monitor_source->thread_info.fixed_latency == s->thread_info.fixed_latency);
733 pa_assert(s->monitor_source->thread_info.min_latency == s->thread_info.min_latency);
734 pa_assert(s->monitor_source->thread_info.max_latency == s->thread_info.max_latency);
736 if (s->suspend_cause)
737 pa_assert_se(sink_set_state(s, PA_SINK_SUSPENDED) == 0);
739 pa_assert_se(sink_set_state(s, PA_SINK_IDLE) == 0);
741 pa_source_put(s->monitor_source);
743 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
744 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PUT], s);
746 /* This function must be called after the PA_CORE_HOOK_SINK_PUT hook,
747 * because module-switch-on-connect needs to know the old default sink */
748 pa_core_update_default_sink(s->core);
751 /* Called from main context */
752 void pa_sink_unlink(pa_sink* s) {
754 pa_sink_input *i, PA_UNUSED *j = NULL;
756 pa_sink_assert_ref(s);
757 pa_assert_ctl_context();
759 /* Please note that pa_sink_unlink() does more than simply
760 * reversing pa_sink_put(). It also undoes the registrations
761 * already done in pa_sink_new()! */
763 if (s->unlink_requested)
766 s->unlink_requested = true;
768 linked = PA_SINK_IS_LINKED(s->state);
771 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK], s);
773 if (s->state != PA_SINK_UNLINKED)
774 pa_namereg_unregister(s->core, s->name);
775 pa_idxset_remove_by_data(s->core->sinks, s, NULL);
777 pa_core_update_default_sink(s->core);
780 pa_idxset_remove_by_data(s->card->sinks, s, NULL);
782 while ((i = pa_idxset_first(s->inputs, NULL))) {
784 pa_sink_input_kill(i);
789 sink_set_state(s, PA_SINK_UNLINKED);
791 s->state = PA_SINK_UNLINKED;
795 if (s->monitor_source)
796 pa_source_unlink(s->monitor_source);
799 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index);
800 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_UNLINK_POST], s);
804 /* Called from main context */
805 static void sink_free(pa_object *o) {
806 pa_sink *s = PA_SINK(o);
809 pa_assert_ctl_context();
810 pa_assert(pa_sink_refcnt(s) == 0);
811 pa_assert(!PA_SINK_IS_LINKED(s->state));
813 pa_log_info("Freeing sink %u \"%s\"", s->index, s->name);
815 pa_sink_volume_change_flush(s);
817 if (s->monitor_source) {
818 pa_source_unref(s->monitor_source);
819 s->monitor_source = NULL;
822 pa_idxset_free(s->inputs, NULL);
823 pa_hashmap_free(s->thread_info.inputs);
825 if (s->silence.memblock)
826 pa_memblock_unref(s->silence.memblock);
832 pa_proplist_free(s->proplist);
835 pa_hashmap_free(s->ports);
837 #ifdef TIZEN_PCM_DUMP
838 /* close file for dump pcm */
839 if (s->pcm_dump_fp) {
840 fclose(s->pcm_dump_fp);
841 pa_log_info("%s closed", s->dump_path);
842 pa_xfree(s->dump_path);
843 s->pcm_dump_fp = NULL;
849 /* Called from main context, and not while the IO thread is active, please */
850 void pa_sink_set_asyncmsgq(pa_sink *s, pa_asyncmsgq *q) {
851 pa_sink_assert_ref(s);
852 pa_assert_ctl_context();
856 if (s->monitor_source)
857 pa_source_set_asyncmsgq(s->monitor_source, q);
860 /* Called from main context, and not while the IO thread is active, please */
861 void pa_sink_update_flags(pa_sink *s, pa_sink_flags_t mask, pa_sink_flags_t value) {
862 pa_sink_flags_t old_flags;
863 pa_sink_input *input;
866 pa_sink_assert_ref(s);
867 pa_assert_ctl_context();
869 /* For now, allow only a minimal set of flags to be changed. */
870 pa_assert((mask & ~(PA_SINK_DYNAMIC_LATENCY|PA_SINK_LATENCY)) == 0);
872 old_flags = s->flags;
873 s->flags = (s->flags & ~mask) | (value & mask);
875 if (s->flags == old_flags)
878 if ((s->flags & PA_SINK_LATENCY) != (old_flags & PA_SINK_LATENCY))
879 pa_log_debug("Sink %s: LATENCY flag %s.", s->name, (s->flags & PA_SINK_LATENCY) ? "enabled" : "disabled");
881 if ((s->flags & PA_SINK_DYNAMIC_LATENCY) != (old_flags & PA_SINK_DYNAMIC_LATENCY))
882 pa_log_debug("Sink %s: DYNAMIC_LATENCY flag %s.",
883 s->name, (s->flags & PA_SINK_DYNAMIC_LATENCY) ? "enabled" : "disabled");
885 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
886 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_FLAGS_CHANGED], s);
888 if (s->monitor_source)
889 pa_source_update_flags(s->monitor_source,
890 ((mask & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
891 ((mask & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0),
892 ((value & PA_SINK_LATENCY) ? PA_SOURCE_LATENCY : 0) |
893 ((value & PA_SINK_DYNAMIC_LATENCY) ? PA_SOURCE_DYNAMIC_LATENCY : 0));
895 PA_IDXSET_FOREACH(input, s->inputs, idx) {
896 if (input->origin_sink)
897 pa_sink_update_flags(input->origin_sink, mask, value);
901 /* Called from IO context, or before _put() from main context */
902 void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
903 pa_sink_assert_ref(s);
904 pa_sink_assert_io_context(s);
906 s->thread_info.rtpoll = p;
908 if (s->monitor_source)
909 pa_source_set_rtpoll(s->monitor_source, p);
912 /* Called from main context */
913 int pa_sink_update_status(pa_sink*s) {
914 pa_sink_assert_ref(s);
915 pa_assert_ctl_context();
916 pa_assert(PA_SINK_IS_LINKED(s->state));
918 if (s->state == PA_SINK_SUSPENDED)
921 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
924 /* Called from any context - must be threadsafe */
925 void pa_sink_set_mixer_dirty(pa_sink *s, bool is_dirty) {
926 pa_atomic_store(&s->mixer_dirty, is_dirty ? 1 : 0);
929 /* Called from main context */
930 int pa_sink_suspend(pa_sink *s, bool suspend, pa_suspend_cause_t cause) {
931 pa_sink_assert_ref(s);
932 pa_assert_ctl_context();
933 pa_assert(PA_SINK_IS_LINKED(s->state));
934 pa_assert(cause != 0);
937 s->suspend_cause |= cause;
938 s->monitor_source->suspend_cause |= cause;
940 s->suspend_cause &= ~cause;
941 s->monitor_source->suspend_cause &= ~cause;
944 if (!(s->suspend_cause & PA_SUSPEND_SESSION) && (pa_atomic_load(&s->mixer_dirty) != 0)) {
945 /* This might look racy but isn't: If somebody sets mixer_dirty exactly here,
946 it'll be handled just fine. */
947 pa_sink_set_mixer_dirty(s, false);
948 pa_log_debug("Mixer is now accessible. Updating alsa mixer settings.");
949 if (s->active_port && s->set_port) {
950 if (s->flags & PA_SINK_DEFERRED_VOLUME) {
951 struct sink_message_set_port msg = { .port = s->active_port, .ret = 0 };
952 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0);
955 s->set_port(s, s->active_port);
965 if ((pa_sink_get_state(s) == PA_SINK_SUSPENDED) == !!s->suspend_cause)
968 pa_log_debug("Suspend cause of sink %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
970 if (s->suspend_cause)
971 return sink_set_state(s, PA_SINK_SUSPENDED);
973 return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
976 /* Called from main context */
977 pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) {
978 pa_sink_input *i, *n;
981 pa_sink_assert_ref(s);
982 pa_assert_ctl_context();
983 pa_assert(PA_SINK_IS_LINKED(s->state));
988 for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
989 n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
991 pa_sink_input_ref(i);
993 if (pa_sink_input_start_move(i) >= 0)
996 pa_sink_input_unref(i);
1002 /* Called from main context */
1003 void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, bool save) {
1006 pa_sink_assert_ref(s);
1007 pa_assert_ctl_context();
1008 pa_assert(PA_SINK_IS_LINKED(s->state));
1011 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
1012 if (pa_sink_input_finish_move(i, s, save) < 0)
1013 pa_sink_input_fail_move(i);
1015 pa_sink_input_unref(i);
1018 pa_queue_free(q, NULL);
1021 /* Called from main context */
1022 void pa_sink_move_all_fail(pa_queue *q) {
1025 pa_assert_ctl_context();
1028 while ((i = PA_SINK_INPUT(pa_queue_pop(q)))) {
1029 pa_sink_input_fail_move(i);
1030 pa_sink_input_unref(i);
1033 pa_queue_free(q, NULL);
1036 /* Called from IO thread context */
1037 size_t pa_sink_process_input_underruns(pa_sink *s, size_t left_to_play) {
1042 pa_sink_assert_ref(s);
1043 pa_sink_assert_io_context(s);
1045 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
1046 size_t uf = i->thread_info.underrun_for_sink;
1048 /* Propagate down the filter tree */
1049 if (i->origin_sink) {
1050 size_t filter_result, left_to_play_origin;
1052 /* The recursive call works in the origin sink domain ... */
1053 left_to_play_origin = pa_convert_size(left_to_play, &i->sink->sample_spec, &i->origin_sink->sample_spec);
1055 /* .. and returns the time to sleep before waking up. We need the
1056 * underrun duration for comparisons, so we undo the subtraction on
1057 * the return value... */
1058 filter_result = left_to_play_origin - pa_sink_process_input_underruns(i->origin_sink, left_to_play_origin);
1060 /* ... and convert it back to the master sink domain */
1061 filter_result = pa_convert_size(filter_result, &i->origin_sink->sample_spec, &i->sink->sample_spec);
1063 /* Remember the longest underrun so far */
1064 if (filter_result > result)
1065 result = filter_result;
1069 /* No underrun here, move on */
1071 } else if (uf >= left_to_play) {
1072 /* The sink has possibly consumed all the data the sink input provided */
1073 pa_sink_input_process_underrun(i);
1074 } else if (uf > result) {
1075 /* Remember the longest underrun so far */
1081 pa_log_debug("%s: Found underrun %ld bytes ago (%ld bytes ahead in playback buffer)", s->name,
1082 (long) result, (long) left_to_play - result);
1083 return left_to_play - result;
1086 /* Called from IO thread context */
1087 void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
1091 pa_sink_assert_ref(s);
1092 pa_sink_assert_io_context(s);
1093 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1095 /* If nobody requested this and this is actually no real rewind
1096 * then we can short cut this. Please note that this means that
1097 * not all rewind requests triggered upstream will always be
1098 * translated in actual requests! */
1099 if (!s->thread_info.rewind_requested && nbytes <= 0)
1102 s->thread_info.rewind_nbytes = 0;
1103 s->thread_info.rewind_requested = false;
1106 pa_log_debug("Processing rewind...");
1107 if (s->flags & PA_SINK_DEFERRED_VOLUME)
1108 pa_sink_volume_change_rewind(s, nbytes);
1109 #ifdef TIZEN_PCM_DUMP
1112 fseeko(s->pcm_dump_fp, (off_t)nbytes * (-1), SEEK_CUR);
1116 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
1117 pa_sink_input_assert_ref(i);
1118 pa_sink_input_process_rewind(i, nbytes);
1122 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
1123 pa_source_process_rewind(s->monitor_source, nbytes);
1127 /* Called from IO thread context */
1128 static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, unsigned maxinfo) {
1132 size_t mixlength = *length;
1134 pa_sink_assert_ref(s);
1135 pa_sink_assert_io_context(s);
1138 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
1139 pa_sink_input_assert_ref(i);
1141 pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
1143 if (mixlength == 0 || info->chunk.length < mixlength)
1144 mixlength = info->chunk.length;
1146 if (pa_memblock_is_silence(info->chunk.memblock)) {
1147 pa_memblock_unref(info->chunk.memblock);
1151 info->userdata = pa_sink_input_ref(i);
1153 pa_assert(info->chunk.memblock);
1154 pa_assert(info->chunk.length > 0);
1162 *length = mixlength;
1167 /* Called from IO thread context */
1168 static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
1172 unsigned n_unreffed = 0;
1174 pa_sink_assert_ref(s);
1175 pa_sink_assert_io_context(s);
1177 pa_assert(result->memblock);
1178 pa_assert(result->length > 0);
1180 /* We optimize for the case where the order of the inputs has not changed */
1182 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
1184 pa_mix_info* m = NULL;
1186 pa_sink_input_assert_ref(i);
1188 /* Let's try to find the matching entry info the pa_mix_info array */
1189 for (j = 0; j < n; j ++) {
1191 if (info[p].userdata == i) {
1201 /* Drop read data */
1202 pa_sink_input_drop(i, result->length);
1204 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
1206 if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
1207 void *ostate = NULL;
1208 pa_source_output *o;
1211 if (m && m->chunk.memblock) {
1213 pa_memblock_ref(c.memblock);
1214 pa_assert(result->length <= c.length);
1215 c.length = result->length;
1217 pa_memchunk_make_writable(&c, 0);
1218 pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
1221 pa_memblock_ref(c.memblock);
1222 pa_assert(result->length <= c.length);
1223 c.length = result->length;
1226 while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
1227 pa_source_output_assert_ref(o);
1228 pa_assert(o->direct_on_input == i);
1229 pa_source_post_direct(s->monitor_source, o, &c);
1232 pa_memblock_unref(c.memblock);
1237 if (m->chunk.memblock) {
1238 pa_memblock_unref(m->chunk.memblock);
1239 pa_memchunk_reset(&m->chunk);
1242 pa_sink_input_unref(m->userdata);
1249 /* Now drop references to entries that are included in the
1250 * pa_mix_info array but don't exist anymore */
1252 if (n_unreffed < n) {
1253 for (; n > 0; info++, n--) {
1255 pa_sink_input_unref(info->userdata);
1256 if (info->chunk.memblock)
1257 pa_memblock_unref(info->chunk.memblock);
1261 if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
1262 pa_source_post(s->monitor_source, result);
1265 /* Called from IO thread context */
1266 void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
1267 pa_mix_info info[MAX_MIX_CHANNELS];
1269 size_t block_size_max;
1271 pa_sink_assert_ref(s);
1272 pa_sink_assert_io_context(s);
1273 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1274 pa_assert(pa_frame_aligned(length, &s->sample_spec));
1277 pa_assert(!s->thread_info.rewind_requested);
1278 pa_assert(s->thread_info.rewind_nbytes == 0);
1280 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1281 result->memblock = pa_memblock_ref(s->silence.memblock);
1282 result->index = s->silence.index;
1283 result->length = PA_MIN(s->silence.length, length);
1290 length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
1292 block_size_max = pa_mempool_block_size_max(s->core->mempool);
1293 if (length > block_size_max)
1294 length = pa_frame_align(block_size_max, &s->sample_spec);
1296 pa_assert(length > 0);
1298 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
1302 *result = s->silence;
1303 pa_memblock_ref(result->memblock);
1305 if (result->length > length)
1306 result->length = length;
1308 } else if (n == 1) {
1311 *result = info[0].chunk;
1312 pa_memblock_ref(result->memblock);
1314 if (result->length > length)
1315 result->length = length;
1317 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
1319 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
1320 pa_memblock_unref(result->memblock);
1321 pa_silence_memchunk_get(&s->core->silence_cache,
1326 } else if (!pa_cvolume_is_norm(&volume)) {
1327 pa_memchunk_make_writable(result, 0);
1328 pa_volume_memchunk(result, &s->sample_spec, &volume);
1332 result->memblock = pa_memblock_new(s->core->mempool, length);
1334 ptr = pa_memblock_acquire(result->memblock);
1335 result->length = pa_mix(info, n,
1338 &s->thread_info.soft_volume,
1339 s->thread_info.soft_muted);
1340 pa_memblock_release(result->memblock);
1345 inputs_drop(s, info, n, result);
1347 #ifdef TIZEN_PCM_DUMP
1348 pa_sink_write_pcm_dump(s, result);
1353 /* Called from IO thread context */
1354 void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
1355 pa_mix_info info[MAX_MIX_CHANNELS];
1357 size_t length, block_size_max;
1359 pa_sink_assert_ref(s);
1360 pa_sink_assert_io_context(s);
1361 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1363 pa_assert(target->memblock);
1364 pa_assert(target->length > 0);
1365 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
1367 pa_assert(!s->thread_info.rewind_requested);
1368 pa_assert(s->thread_info.rewind_nbytes == 0);
1370 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1371 pa_silence_memchunk(target, &s->sample_spec);
1377 length = target->length;
1378 block_size_max = pa_mempool_block_size_max(s->core->mempool);
1379 if (length > block_size_max)
1380 length = pa_frame_align(block_size_max, &s->sample_spec);
1382 pa_assert(length > 0);
1384 n = fill_mix_info(s, &length, info, MAX_MIX_CHANNELS);
1387 if (target->length > length)
1388 target->length = length;
1390 pa_silence_memchunk(target, &s->sample_spec);
1391 } else if (n == 1) {
1394 if (target->length > length)
1395 target->length = length;
1397 pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
1399 if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume))
1400 pa_silence_memchunk(target, &s->sample_spec);
1404 vchunk = info[0].chunk;
1405 pa_memblock_ref(vchunk.memblock);
1407 if (vchunk.length > length)
1408 vchunk.length = length;
1410 if (!pa_cvolume_is_norm(&volume)) {
1411 pa_memchunk_make_writable(&vchunk, 0);
1412 pa_volume_memchunk(&vchunk, &s->sample_spec, &volume);
1415 pa_memchunk_memcpy(target, &vchunk);
1416 pa_memblock_unref(vchunk.memblock);
1422 ptr = pa_memblock_acquire(target->memblock);
1424 target->length = pa_mix(info, n,
1425 (uint8_t*) ptr + target->index, length,
1427 &s->thread_info.soft_volume,
1428 s->thread_info.soft_muted);
1430 pa_memblock_release(target->memblock);
1433 inputs_drop(s, info, n, target);
1435 #ifdef TIZEN_PCM_DUMP
1436 pa_sink_write_pcm_dump(s, target);
1441 /* Called from IO thread context */
1442 void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
1446 pa_sink_assert_ref(s);
1447 pa_sink_assert_io_context(s);
1448 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1450 pa_assert(target->memblock);
1451 pa_assert(target->length > 0);
1452 pa_assert(pa_frame_aligned(target->length, &s->sample_spec));
1454 pa_assert(!s->thread_info.rewind_requested);
1455 pa_assert(s->thread_info.rewind_nbytes == 0);
1457 if (s->thread_info.state == PA_SINK_SUSPENDED) {
1458 pa_silence_memchunk(target, &s->sample_spec);
1471 pa_sink_render_into(s, &chunk);
1480 /* Called from IO thread context */
1481 void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
1482 pa_sink_assert_ref(s);
1483 pa_sink_assert_io_context(s);
1484 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1485 pa_assert(length > 0);
1486 pa_assert(pa_frame_aligned(length, &s->sample_spec));
1489 pa_assert(!s->thread_info.rewind_requested);
1490 pa_assert(s->thread_info.rewind_nbytes == 0);
1494 pa_sink_render(s, length, result);
1496 if (result->length < length) {
1499 pa_memchunk_make_writable(result, length);
1501 chunk.memblock = result->memblock;
1502 chunk.index = result->index + result->length;
1503 chunk.length = length - result->length;
1505 pa_sink_render_into_full(s, &chunk);
1507 result->length = length;
1513 /* Called from main thread */
1514 int pa_sink_update_rate(pa_sink *s, uint32_t rate, bool passthrough) {
1516 uint32_t desired_rate;
1517 uint32_t default_rate = s->default_sample_rate;
1518 uint32_t alternate_rate = s->alternate_sample_rate;
1521 bool default_rate_is_usable = false;
1522 bool alternate_rate_is_usable = false;
1523 bool avoid_resampling = s->core->avoid_resampling;
1525 if (rate == s->sample_spec.rate)
1528 if (!s->update_rate)
1531 if (PA_UNLIKELY(default_rate == alternate_rate && !passthrough && !avoid_resampling)) {
1532 pa_log_debug("Default and alternate sample rates are the same, so there is no point in switching.");
1536 if (PA_SINK_IS_RUNNING(s->state)) {
1537 pa_log_info("Cannot update rate, SINK_IS_RUNNING, will keep using %u Hz",
1538 s->sample_spec.rate);
1542 if (s->monitor_source) {
1543 if (PA_SOURCE_IS_RUNNING(s->monitor_source->state) == true) {
1544 pa_log_info("Cannot update rate, monitor source is RUNNING");
1549 if (PA_UNLIKELY(!pa_sample_rate_valid(rate)))
1553 /* We have to try to use the sink input rate */
1554 desired_rate = rate;
1556 } else if (avoid_resampling && (rate >= default_rate || rate >= alternate_rate)) {
1557 /* We just try to set the sink input's sample rate if it's not too low */
1558 desired_rate = rate;
1560 } else if (default_rate == rate || alternate_rate == rate) {
1561 /* We can directly try to use this rate */
1562 desired_rate = rate;
1565 /* See if we can pick a rate that results in less resampling effort */
1566 if (default_rate % 11025 == 0 && rate % 11025 == 0)
1567 default_rate_is_usable = true;
1568 if (default_rate % 4000 == 0 && rate % 4000 == 0)
1569 default_rate_is_usable = true;
1570 if (alternate_rate && alternate_rate % 11025 == 0 && rate % 11025 == 0)
1571 alternate_rate_is_usable = true;
1572 if (alternate_rate && alternate_rate % 4000 == 0 && rate % 4000 == 0)
1573 alternate_rate_is_usable = true;
1575 if (alternate_rate_is_usable && !default_rate_is_usable)
1576 desired_rate = alternate_rate;
1578 desired_rate = default_rate;
1581 if (desired_rate == s->sample_spec.rate)
1584 if (!passthrough && pa_sink_used_by(s) > 0)
1587 pa_log_debug("Suspending sink %s due to changing the sample rate.", s->name);
1588 pa_sink_suspend(s, true, PA_SUSPEND_INTERNAL);
1590 if (s->update_rate(s, desired_rate) >= 0) {
1591 /* update monitor source as well */
1592 if (s->monitor_source && !passthrough)
1593 pa_source_update_rate(s->monitor_source, desired_rate, false);
1594 pa_log_info("Changed sampling rate successfully");
1596 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1597 if (i->state == PA_SINK_INPUT_CORKED)
1598 pa_sink_input_update_rate(i);
1604 pa_sink_suspend(s, false, PA_SUSPEND_INTERNAL);
1609 /* Called from main thread */
1610 pa_usec_t pa_sink_get_latency(pa_sink *s) {
1613 pa_sink_assert_ref(s);
1614 pa_assert_ctl_context();
1615 pa_assert(PA_SINK_IS_LINKED(s->state));
1617 /* The returned value is supposed to be in the time domain of the sound card! */
1619 if (s->state == PA_SINK_SUSPENDED)
1622 if (!(s->flags & PA_SINK_LATENCY))
1625 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) == 0);
1627 /* the return value is unsigned, so check that the offset can be added to usec without
1629 if (-s->port_latency_offset <= usec)
1630 usec += s->port_latency_offset;
1634 return (pa_usec_t)usec;
1637 /* Called from IO thread */
1638 int64_t pa_sink_get_latency_within_thread(pa_sink *s, bool allow_negative) {
1642 pa_sink_assert_ref(s);
1643 pa_sink_assert_io_context(s);
1644 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
1646 /* The returned value is supposed to be in the time domain of the sound card! */
1648 if (s->thread_info.state == PA_SINK_SUSPENDED)
1651 if (!(s->flags & PA_SINK_LATENCY))
1654 o = PA_MSGOBJECT(s);
1656 /* FIXME: We probably should make this a proper vtable callback instead of going through process_msg() */
1658 o->process_msg(o, PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL);
1660 /* If allow_negative is false, the call should only return positive values, */
1661 usec += s->thread_info.port_latency_offset;
1662 if (!allow_negative && usec < 0)
1668 /* Called from the main thread (and also from the IO thread while the main
1669 * thread is waiting).
1671 * When a sink uses volume sharing, it never has the PA_SINK_FLAT_VOLUME flag
1672 * set. Instead, flat volume mode is detected by checking whether the root sink
1673 * has the flag set. */
1674 bool pa_sink_flat_volume_enabled(pa_sink *s) {
1675 pa_sink_assert_ref(s);
1677 s = pa_sink_get_master(s);
1680 return (s->flags & PA_SINK_FLAT_VOLUME);
1685 /* Called from the main thread (and also from the IO thread while the main
1686 * thread is waiting). */
1687 pa_sink *pa_sink_get_master(pa_sink *s) {
1688 pa_sink_assert_ref(s);
1690 while (s && (s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
1691 if (PA_UNLIKELY(!s->input_to_master))
1694 s = s->input_to_master->sink;
1700 /* Called from main context */
1701 bool pa_sink_is_filter(pa_sink *s) {
1702 pa_sink_assert_ref(s);
1704 return (s->input_to_master != NULL);
1707 /* Called from main context */
1708 bool pa_sink_is_passthrough(pa_sink *s) {
1709 pa_sink_input *alt_i;
1712 pa_sink_assert_ref(s);
1714 /* one and only one PASSTHROUGH input can possibly be connected */
1715 if (pa_idxset_size(s->inputs) == 1) {
1716 alt_i = pa_idxset_first(s->inputs, &idx);
1718 if (pa_sink_input_is_passthrough(alt_i))
1725 /* Called from main context */
1726 void pa_sink_enter_passthrough(pa_sink *s) {
1729 /* disable the monitor in passthrough mode */
1730 if (s->monitor_source) {
1731 pa_log_debug("Suspending monitor source %s, because the sink is entering the passthrough mode.", s->monitor_source->name);
1732 pa_source_suspend(s->monitor_source, true, PA_SUSPEND_PASSTHROUGH);
1735 /* set the volume to NORM */
1736 s->saved_volume = *pa_sink_get_volume(s, true);
1737 s->saved_save_volume = s->save_volume;
1739 pa_cvolume_set(&volume, s->sample_spec.channels, PA_MIN(s->base_volume, PA_VOLUME_NORM));
1740 pa_sink_set_volume(s, &volume, true, false);
1743 /* Called from main context */
1744 void pa_sink_leave_passthrough(pa_sink *s) {
1745 /* Unsuspend monitor */
1746 if (s->monitor_source) {
1747 pa_log_debug("Resuming monitor source %s, because the sink is leaving the passthrough mode.", s->monitor_source->name);
1748 pa_source_suspend(s->monitor_source, false, PA_SUSPEND_PASSTHROUGH);
1751 /* Restore sink volume to what it was before we entered passthrough mode */
1752 pa_sink_set_volume(s, &s->saved_volume, true, s->saved_save_volume);
1754 pa_cvolume_init(&s->saved_volume);
1755 s->saved_save_volume = false;
1758 /* Called from main context. */
1759 static void compute_reference_ratio(pa_sink_input *i) {
1761 pa_cvolume remapped;
1765 pa_assert(pa_sink_flat_volume_enabled(i->sink));
1768 * Calculates the reference ratio from the sink's reference
1769 * volume. This basically calculates:
1771 * i->reference_ratio = i->volume / i->sink->reference_volume
1774 remapped = i->sink->reference_volume;
1775 pa_cvolume_remap(&remapped, &i->sink->channel_map, &i->channel_map);
1777 ratio = i->reference_ratio;
1779 for (c = 0; c < i->sample_spec.channels; c++) {
1781 /* We don't update when the sink volume is 0 anyway */
1782 if (remapped.values[c] <= PA_VOLUME_MUTED)
1785 /* Don't update the reference ratio unless necessary */
1786 if (pa_sw_volume_multiply(
1788 remapped.values[c]) == i->volume.values[c])
1791 ratio.values[c] = pa_sw_volume_divide(
1792 i->volume.values[c],
1793 remapped.values[c]);
1796 pa_sink_input_set_reference_ratio(i, &ratio);
1799 /* Called from main context. Only called for the root sink in volume sharing
1800 * cases, except for internal recursive calls. */
1801 static void compute_reference_ratios(pa_sink *s) {
1805 pa_sink_assert_ref(s);
1806 pa_assert_ctl_context();
1807 pa_assert(PA_SINK_IS_LINKED(s->state));
1808 pa_assert(pa_sink_flat_volume_enabled(s));
1810 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1811 compute_reference_ratio(i);
1813 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
1814 && PA_SINK_IS_LINKED(i->origin_sink->state))
1815 compute_reference_ratios(i->origin_sink);
1819 /* Called from main context. Only called for the root sink in volume sharing
1820 * cases, except for internal recursive calls. */
1821 static void compute_real_ratios(pa_sink *s) {
1825 pa_sink_assert_ref(s);
1826 pa_assert_ctl_context();
1827 pa_assert(PA_SINK_IS_LINKED(s->state));
1828 pa_assert(pa_sink_flat_volume_enabled(s));
1830 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1832 pa_cvolume remapped;
1834 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
1835 /* The origin sink uses volume sharing, so this input's real ratio
1836 * is handled as a special case - the real ratio must be 0 dB, and
1837 * as a result i->soft_volume must equal i->volume_factor. */
1838 pa_cvolume_reset(&i->real_ratio, i->real_ratio.channels);
1839 i->soft_volume = i->volume_factor;
1841 if (PA_SINK_IS_LINKED(i->origin_sink->state))
1842 compute_real_ratios(i->origin_sink);
1848 * This basically calculates:
1850 * i->real_ratio := i->volume / s->real_volume
1851 * i->soft_volume := i->real_ratio * i->volume_factor
1854 remapped = s->real_volume;
1855 pa_cvolume_remap(&remapped, &s->channel_map, &i->channel_map);
1857 i->real_ratio.channels = i->sample_spec.channels;
1858 i->soft_volume.channels = i->sample_spec.channels;
1860 for (c = 0; c < i->sample_spec.channels; c++) {
1862 if (remapped.values[c] <= PA_VOLUME_MUTED) {
1863 /* We leave i->real_ratio untouched */
1864 i->soft_volume.values[c] = PA_VOLUME_MUTED;
1868 /* Don't lose accuracy unless necessary */
1869 if (pa_sw_volume_multiply(
1870 i->real_ratio.values[c],
1871 remapped.values[c]) != i->volume.values[c])
1873 i->real_ratio.values[c] = pa_sw_volume_divide(
1874 i->volume.values[c],
1875 remapped.values[c]);
1877 i->soft_volume.values[c] = pa_sw_volume_multiply(
1878 i->real_ratio.values[c],
1879 i->volume_factor.values[c]);
1882 /* We don't copy the soft_volume to the thread_info data
1883 * here. That must be done by the caller */
1887 static pa_cvolume *cvolume_remap_minimal_impact(
1889 const pa_cvolume *template,
1890 const pa_channel_map *from,
1891 const pa_channel_map *to) {
1896 pa_assert(template);
1899 pa_assert(pa_cvolume_compatible_with_channel_map(v, from));
1900 pa_assert(pa_cvolume_compatible_with_channel_map(template, to));
1902 /* Much like pa_cvolume_remap(), but tries to minimize impact when
1903 * mapping from sink input to sink volumes:
1905 * If template is a possible remapping from v it is used instead
1906 * of remapping anew.
1908 * If the channel maps don't match we set an all-channel volume on
1909 * the sink to ensure that changing a volume on one stream has no
1910 * effect that cannot be compensated for in another stream that
1911 * does not have the same channel map as the sink. */
1913 if (pa_channel_map_equal(from, to))
1917 if (pa_cvolume_equal(pa_cvolume_remap(&t, to, from), v)) {
1922 pa_cvolume_set(v, to->channels, pa_cvolume_max(v));
1926 /* Called from main thread. Only called for the root sink in volume sharing
1927 * cases, except for internal recursive calls. */
1928 static void get_maximum_input_volume(pa_sink *s, pa_cvolume *max_volume, const pa_channel_map *channel_map) {
1932 pa_sink_assert_ref(s);
1933 pa_assert(max_volume);
1934 pa_assert(channel_map);
1935 pa_assert(pa_sink_flat_volume_enabled(s));
1937 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1938 pa_cvolume remapped;
1940 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
1941 if (PA_SINK_IS_LINKED(i->origin_sink->state))
1942 get_maximum_input_volume(i->origin_sink, max_volume, channel_map);
1944 /* Ignore this input. The origin sink uses volume sharing, so this
1945 * input's volume will be set to be equal to the root sink's real
1946 * volume. Obviously this input's current volume must not then
1947 * affect what the root sink's real volume will be. */
1951 remapped = i->volume;
1952 cvolume_remap_minimal_impact(&remapped, max_volume, &i->channel_map, channel_map);
1953 pa_cvolume_merge(max_volume, max_volume, &remapped);
1957 /* Called from main thread. Only called for the root sink in volume sharing
1958 * cases, except for internal recursive calls. */
1959 static bool has_inputs(pa_sink *s) {
1963 pa_sink_assert_ref(s);
1965 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1966 if (!i->origin_sink || !(i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER) || has_inputs(i->origin_sink))
1973 /* Called from main thread. Only called for the root sink in volume sharing
1974 * cases, except for internal recursive calls. */
1975 static void update_real_volume(pa_sink *s, const pa_cvolume *new_volume, pa_channel_map *channel_map) {
1979 pa_sink_assert_ref(s);
1980 pa_assert(new_volume);
1981 pa_assert(channel_map);
1983 s->real_volume = *new_volume;
1984 pa_cvolume_remap(&s->real_volume, channel_map, &s->channel_map);
1986 PA_IDXSET_FOREACH(i, s->inputs, idx) {
1987 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
1988 if (pa_sink_flat_volume_enabled(s)) {
1989 pa_cvolume new_input_volume;
1991 /* Follow the root sink's real volume. */
1992 new_input_volume = *new_volume;
1993 pa_cvolume_remap(&new_input_volume, channel_map, &i->channel_map);
1994 pa_sink_input_set_volume_direct(i, &new_input_volume);
1995 compute_reference_ratio(i);
1998 if (PA_SINK_IS_LINKED(i->origin_sink->state))
1999 update_real_volume(i->origin_sink, new_volume, channel_map);
2004 /* Called from main thread. Only called for the root sink in shared volume
2006 static void compute_real_volume(pa_sink *s) {
2007 pa_sink_assert_ref(s);
2008 pa_assert_ctl_context();
2009 pa_assert(PA_SINK_IS_LINKED(s->state));
2010 pa_assert(pa_sink_flat_volume_enabled(s));
2011 pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
2013 /* This determines the maximum volume of all streams and sets
2014 * s->real_volume accordingly. */
2016 if (!has_inputs(s)) {
2017 /* In the special case that we have no sink inputs we leave the
2018 * volume unmodified. */
2019 update_real_volume(s, &s->reference_volume, &s->channel_map);
2023 pa_cvolume_mute(&s->real_volume, s->channel_map.channels);
2025 /* First let's determine the new maximum volume of all inputs
2026 * connected to this sink */
2027 get_maximum_input_volume(s, &s->real_volume, &s->channel_map);
2028 update_real_volume(s, &s->real_volume, &s->channel_map);
2030 /* Then, let's update the real ratios/soft volumes of all inputs
2031 * connected to this sink */
2032 compute_real_ratios(s);
2035 /* Called from main thread. Only called for the root sink in shared volume
2036 * cases, except for internal recursive calls. */
2037 static void propagate_reference_volume(pa_sink *s) {
2041 pa_sink_assert_ref(s);
2042 pa_assert_ctl_context();
2043 pa_assert(PA_SINK_IS_LINKED(s->state));
2044 pa_assert(pa_sink_flat_volume_enabled(s));
2046 /* This is called whenever the sink volume changes that is not
2047 * caused by a sink input volume change. We need to fix up the
2048 * sink input volumes accordingly */
2050 PA_IDXSET_FOREACH(i, s->inputs, idx) {
2051 pa_cvolume new_volume;
2053 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
2054 if (PA_SINK_IS_LINKED(i->origin_sink->state))
2055 propagate_reference_volume(i->origin_sink);
2057 /* Since the origin sink uses volume sharing, this input's volume
2058 * needs to be updated to match the root sink's real volume, but
2059 * that will be done later in update_real_volume(). */
2063 /* This basically calculates:
2065 * i->volume := s->reference_volume * i->reference_ratio */
2067 new_volume = s->reference_volume;
2068 pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map);
2069 pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
2070 pa_sink_input_set_volume_direct(i, &new_volume);
2074 /* Called from main thread. Only called for the root sink in volume sharing
2075 * cases, except for internal recursive calls. The return value indicates
2076 * whether any reference volume actually changed. */
2077 static bool update_reference_volume(pa_sink *s, const pa_cvolume *v, const pa_channel_map *channel_map, bool save) {
2079 bool reference_volume_changed;
2083 pa_sink_assert_ref(s);
2084 pa_assert(PA_SINK_IS_LINKED(s->state));
2086 pa_assert(channel_map);
2087 pa_assert(pa_cvolume_valid(v));
2090 pa_cvolume_remap(&volume, channel_map, &s->channel_map);
2092 reference_volume_changed = !pa_cvolume_equal(&volume, &s->reference_volume);
2093 pa_sink_set_reference_volume_direct(s, &volume);
2095 s->save_volume = (!reference_volume_changed && s->save_volume) || save;
2097 if (!reference_volume_changed && !(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
2098 /* If the root sink's volume doesn't change, then there can't be any
2099 * changes in the other sinks in the sink tree either.
2101 * It's probably theoretically possible that even if the root sink's
2102 * volume changes slightly, some filter sink doesn't change its volume
2103 * due to rounding errors. If that happens, we still want to propagate
2104 * the changed root sink volume to the sinks connected to the
2105 * intermediate sink that didn't change its volume. This theoretical
2106 * possibility is the reason why we have that !(s->flags &
2107 * PA_SINK_SHARE_VOLUME_WITH_MASTER) condition. Probably nobody would
2108 * notice even if we returned here false always if
2109 * reference_volume_changed is false. */
2112 PA_IDXSET_FOREACH(i, s->inputs, idx) {
2113 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
2114 && PA_SINK_IS_LINKED(i->origin_sink->state))
2115 update_reference_volume(i->origin_sink, v, channel_map, false);
2121 /* Called from main thread */
2122 void pa_sink_set_volume(
2124 const pa_cvolume *volume,
2128 pa_cvolume new_reference_volume;
2131 pa_sink_assert_ref(s);
2132 pa_assert_ctl_context();
2133 pa_assert(PA_SINK_IS_LINKED(s->state));
2134 pa_assert(!volume || pa_cvolume_valid(volume));
2135 pa_assert(volume || pa_sink_flat_volume_enabled(s));
2136 pa_assert(!volume || volume->channels == 1 || pa_cvolume_compatible(volume, &s->sample_spec));
2138 /* make sure we don't change the volume when a PASSTHROUGH input is connected ...
2139 * ... *except* if we're being invoked to reset the volume to ensure 0 dB gain */
2140 if (pa_sink_is_passthrough(s) && (!volume || !pa_cvolume_is_norm(volume))) {
2141 pa_log_warn("Cannot change volume, Sink is connected to PASSTHROUGH input");
2145 /* In case of volume sharing, the volume is set for the root sink first,
2146 * from which it's then propagated to the sharing sinks. */
2147 root_sink = pa_sink_get_master(s);
2149 if (PA_UNLIKELY(!root_sink))
2152 /* As a special exception we accept mono volumes on all sinks --
2153 * even on those with more complex channel maps */
2156 if (pa_cvolume_compatible(volume, &s->sample_spec))
2157 new_reference_volume = *volume;
2159 new_reference_volume = s->reference_volume;
2160 pa_cvolume_scale(&new_reference_volume, pa_cvolume_max(volume));
2163 pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
2165 if (update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save)) {
2166 if (pa_sink_flat_volume_enabled(root_sink)) {
2167 /* OK, propagate this volume change back to the inputs */
2168 propagate_reference_volume(root_sink);
2170 /* And now recalculate the real volume */
2171 compute_real_volume(root_sink);
2173 update_real_volume(root_sink, &root_sink->reference_volume, &root_sink->channel_map);
2177 /* If volume is NULL we synchronize the sink's real and
2178 * reference volumes with the stream volumes. */
2180 pa_assert(pa_sink_flat_volume_enabled(root_sink));
2182 /* Ok, let's determine the new real volume */
2183 compute_real_volume(root_sink);
2185 /* Let's 'push' the reference volume if necessary */
2186 pa_cvolume_merge(&new_reference_volume, &s->reference_volume, &root_sink->real_volume);
2187 /* If the sink and its root don't have the same number of channels, we need to remap */
2188 if (s != root_sink && !pa_channel_map_equal(&s->channel_map, &root_sink->channel_map))
2189 pa_cvolume_remap(&new_reference_volume, &s->channel_map, &root_sink->channel_map);
2190 update_reference_volume(root_sink, &new_reference_volume, &root_sink->channel_map, save);
2192 /* Now that the reference volume is updated, we can update the streams'
2193 * reference ratios. */
2194 compute_reference_ratios(root_sink);
2197 if (root_sink->set_volume) {
2198 /* If we have a function set_volume(), then we do not apply a
2199 * soft volume by default. However, set_volume() is free to
2200 * apply one to root_sink->soft_volume */
2202 pa_cvolume_reset(&root_sink->soft_volume, root_sink->sample_spec.channels);
2203 if (!(root_sink->flags & PA_SINK_DEFERRED_VOLUME))
2204 root_sink->set_volume(root_sink);
2207 /* If we have no function set_volume(), then the soft volume
2208 * becomes the real volume */
2209 root_sink->soft_volume = root_sink->real_volume;
2211 /* This tells the sink that soft volume and/or real volume changed */
2213 pa_assert_se(pa_asyncmsgq_send(root_sink->asyncmsgq, PA_MSGOBJECT(root_sink), PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL) == 0);
2216 /* Called from the io thread if sync volume is used, otherwise from the main thread.
2217 * Only to be called by sink implementor */
2218 void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume) {
2220 pa_sink_assert_ref(s);
2221 pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
2223 if (s->flags & PA_SINK_DEFERRED_VOLUME)
2224 pa_sink_assert_io_context(s);
2226 pa_assert_ctl_context();
2229 pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
2231 s->soft_volume = *volume;
2233 if (PA_SINK_IS_LINKED(s->state) && !(s->flags & PA_SINK_DEFERRED_VOLUME))
2234 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME, NULL, 0, NULL) == 0);
2236 s->thread_info.soft_volume = s->soft_volume;
2239 /* Called from the main thread. Only called for the root sink in volume sharing
2240 * cases, except for internal recursive calls. */
2241 static void propagate_real_volume(pa_sink *s, const pa_cvolume *old_real_volume) {
2245 pa_sink_assert_ref(s);
2246 pa_assert(old_real_volume);
2247 pa_assert_ctl_context();
2248 pa_assert(PA_SINK_IS_LINKED(s->state));
2250 /* This is called when the hardware's real volume changes due to
2251 * some external event. We copy the real volume into our
2252 * reference volume and then rebuild the stream volumes based on
2253 * i->real_ratio which should stay fixed. */
2255 if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
2256 if (pa_cvolume_equal(old_real_volume, &s->real_volume))
2259 /* 1. Make the real volume the reference volume */
2260 update_reference_volume(s, &s->real_volume, &s->channel_map, true);
2263 if (pa_sink_flat_volume_enabled(s)) {
2265 PA_IDXSET_FOREACH(i, s->inputs, idx) {
2266 pa_cvolume new_volume;
2268 /* 2. Since the sink's reference and real volumes are equal
2269 * now our ratios should be too. */
2270 pa_sink_input_set_reference_ratio(i, &i->real_ratio);
2272 /* 3. Recalculate the new stream reference volume based on the
2273 * reference ratio and the sink's reference volume.
2275 * This basically calculates:
2277 * i->volume = s->reference_volume * i->reference_ratio
2279 * This is identical to propagate_reference_volume() */
2280 new_volume = s->reference_volume;
2281 pa_cvolume_remap(&new_volume, &s->channel_map, &i->channel_map);
2282 pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
2283 pa_sink_input_set_volume_direct(i, &new_volume);
2285 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)
2286 && PA_SINK_IS_LINKED(i->origin_sink->state))
2287 propagate_real_volume(i->origin_sink, old_real_volume);
2291 /* Something got changed in the hardware. It probably makes sense
2292 * to save changed hw settings given that hw volume changes not
2293 * triggered by PA are almost certainly done by the user. */
2294 if (!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
2295 s->save_volume = true;
2298 /* Called from io thread */
2299 void pa_sink_update_volume_and_mute(pa_sink *s) {
2301 pa_sink_assert_io_context(s);
2303 pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE, NULL, 0, NULL, NULL);
2306 /* Called from main thread */
2307 const pa_cvolume *pa_sink_get_volume(pa_sink *s, bool force_refresh) {
2308 pa_sink_assert_ref(s);
2309 pa_assert_ctl_context();
2310 pa_assert(PA_SINK_IS_LINKED(s->state));
2312 if (s->refresh_volume || force_refresh) {
2313 struct pa_cvolume old_real_volume;
2315 pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
2317 old_real_volume = s->real_volume;
2319 if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_volume)
2322 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_VOLUME, NULL, 0, NULL) == 0);
2324 update_real_volume(s, &s->real_volume, &s->channel_map);
2325 propagate_real_volume(s, &old_real_volume);
2328 return &s->reference_volume;
2331 /* Called from main thread. In volume sharing cases, only the root sink may
2333 void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_real_volume) {
2334 pa_cvolume old_real_volume;
2336 pa_sink_assert_ref(s);
2337 pa_assert_ctl_context();
2338 pa_assert(PA_SINK_IS_LINKED(s->state));
2339 pa_assert(!(s->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER));
2341 /* The sink implementor may call this if the volume changed to make sure everyone is notified */
2343 old_real_volume = s->real_volume;
2344 update_real_volume(s, new_real_volume, &s->channel_map);
2345 propagate_real_volume(s, &old_real_volume);
2348 /* Called from main thread */
2349 void pa_sink_set_mute(pa_sink *s, bool mute, bool save) {
2352 pa_sink_assert_ref(s);
2353 pa_assert_ctl_context();
2355 old_muted = s->muted;
2357 if (mute == old_muted) {
2358 s->save_muted |= save;
2363 s->save_muted = save;
2365 if (!(s->flags & PA_SINK_DEFERRED_VOLUME) && s->set_mute) {
2366 s->set_mute_in_progress = true;
2368 s->set_mute_in_progress = false;
2371 if (!PA_SINK_IS_LINKED(s->state))
2374 pa_log_debug("The mute of sink %s changed from %s to %s.", s->name, pa_yes_no(old_muted), pa_yes_no(mute));
2375 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
2376 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
2377 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_MUTE_CHANGED], s);
2380 /* Called from main thread */
2381 bool pa_sink_get_mute(pa_sink *s, bool force_refresh) {
2383 pa_sink_assert_ref(s);
2384 pa_assert_ctl_context();
2385 pa_assert(PA_SINK_IS_LINKED(s->state));
2387 if ((s->refresh_muted || force_refresh) && s->get_mute) {
2390 if (s->flags & PA_SINK_DEFERRED_VOLUME) {
2391 if (pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, &mute, 0, NULL) >= 0)
2392 pa_sink_mute_changed(s, mute);
2394 if (s->get_mute(s, &mute) >= 0)
2395 pa_sink_mute_changed(s, mute);
2402 /* Called from main thread */
2403 void pa_sink_mute_changed(pa_sink *s, bool new_muted) {
2404 pa_sink_assert_ref(s);
2405 pa_assert_ctl_context();
2406 pa_assert(PA_SINK_IS_LINKED(s->state));
2408 if (s->set_mute_in_progress)
2411 /* pa_sink_set_mute() does this same check, so this may appear redundant,
2412 * but we must have this here also, because the save parameter of
2413 * pa_sink_set_mute() would otherwise have unintended side effects (saving
2414 * the mute state when it shouldn't be saved). */
2415 if (new_muted == s->muted)
2418 pa_sink_set_mute(s, new_muted, true);
2421 /* Called from main thread */
2422 bool pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
2423 pa_sink_assert_ref(s);
2424 pa_assert_ctl_context();
2427 pa_proplist_update(s->proplist, mode, p);
2429 if (PA_SINK_IS_LINKED(s->state)) {
2430 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
2431 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
2437 /* Called from main thread */
2438 /* FIXME -- this should be dropped and be merged into pa_sink_update_proplist() */
2439 void pa_sink_set_description(pa_sink *s, const char *description) {
2441 pa_sink_assert_ref(s);
2442 pa_assert_ctl_context();
2444 if (!description && !pa_proplist_contains(s->proplist, PA_PROP_DEVICE_DESCRIPTION))
2447 old = pa_proplist_gets(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
2449 if (old && description && pa_streq(old, description))
2453 pa_proplist_sets(s->proplist, PA_PROP_DEVICE_DESCRIPTION, description);
2455 pa_proplist_unset(s->proplist, PA_PROP_DEVICE_DESCRIPTION);
2457 if (s->monitor_source) {
2460 n = pa_sprintf_malloc("Monitor Source of %s", description ? description : s->name);
2461 pa_source_set_description(s->monitor_source, n);
2465 if (PA_SINK_IS_LINKED(s->state)) {
2466 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
2467 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], s);
2471 /* Called from main thread */
2472 unsigned pa_sink_linked_by(pa_sink *s) {
2475 pa_sink_assert_ref(s);
2476 pa_assert_ctl_context();
2477 pa_assert(PA_SINK_IS_LINKED(s->state));
2479 ret = pa_idxset_size(s->inputs);
2481 /* We add in the number of streams connected to us here. Please
2482 * note the asymmetry to pa_sink_used_by()! */
2484 if (s->monitor_source)
2485 ret += pa_source_linked_by(s->monitor_source);
2490 /* Called from main thread */
2491 unsigned pa_sink_used_by(pa_sink *s) {
2494 pa_sink_assert_ref(s);
2495 pa_assert_ctl_context();
2496 pa_assert(PA_SINK_IS_LINKED(s->state));
2498 ret = pa_idxset_size(s->inputs);
2499 pa_assert(ret >= s->n_corked);
2501 /* Streams connected to our monitor source do not matter for
2502 * pa_sink_used_by()!.*/
2504 return ret - s->n_corked;
2507 /* Called from main thread */
2508 unsigned pa_sink_check_suspend(pa_sink *s, pa_sink_input *ignore_input, pa_source_output *ignore_output) {
2513 pa_sink_assert_ref(s);
2514 pa_assert_ctl_context();
2516 if (!PA_SINK_IS_LINKED(s->state))
2521 PA_IDXSET_FOREACH(i, s->inputs, idx) {
2522 pa_sink_input_state_t st;
2524 if (i == ignore_input)
2527 st = pa_sink_input_get_state(i);
2529 /* We do not assert here. It is perfectly valid for a sink input to
2530 * be in the INIT state (i.e. created, marked done but not yet put)
2531 * and we should not care if it's unlinked as it won't contribute
2532 * towards our busy status.
2534 if (!PA_SINK_INPUT_IS_LINKED(st))
2537 if (st == PA_SINK_INPUT_CORKED)
2540 if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND)
2546 if (s->monitor_source)
2547 ret += pa_source_check_suspend(s->monitor_source, ignore_output);
2552 /* Called from the IO thread */
2553 static void sync_input_volumes_within_thread(pa_sink *s) {
2557 pa_sink_assert_ref(s);
2558 pa_sink_assert_io_context(s);
2560 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
2561 if (pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume))
2564 i->thread_info.soft_volume = i->soft_volume;
2565 pa_sink_input_request_rewind(i, 0, true, false, false);
2569 /* Called from the IO thread. Only called for the root sink in volume sharing
2570 * cases, except for internal recursive calls. */
2571 static void set_shared_volume_within_thread(pa_sink *s) {
2572 pa_sink_input *i = NULL;
2575 pa_sink_assert_ref(s);
2577 PA_MSGOBJECT(s)->process_msg(PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_VOLUME_SYNCED, NULL, 0, NULL);
2579 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state) {
2580 if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
2581 set_shared_volume_within_thread(i->origin_sink);
2585 /* Called from IO thread, except when it is not */
2586 int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
2587 pa_sink *s = PA_SINK(o);
2588 pa_sink_assert_ref(s);
2590 switch ((pa_sink_message_t) code) {
2592 case PA_SINK_MESSAGE_ADD_INPUT: {
2593 pa_sink_input *i = PA_SINK_INPUT(userdata);
2595 /* If you change anything here, make sure to change the
2596 * sink input handling a few lines down at
2597 * PA_SINK_MESSAGE_FINISH_MOVE, too. */
2599 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
2601 /* Since the caller sleeps in pa_sink_input_put(), we can
2602 * safely access data outside of thread_info even though
2605 if ((i->thread_info.sync_prev = i->sync_prev)) {
2606 pa_assert(i->sink == i->thread_info.sync_prev->sink);
2607 pa_assert(i->sync_prev->sync_next == i);
2608 i->thread_info.sync_prev->thread_info.sync_next = i;
2611 if ((i->thread_info.sync_next = i->sync_next)) {
2612 pa_assert(i->sink == i->thread_info.sync_next->sink);
2613 pa_assert(i->sync_next->sync_prev == i);
2614 i->thread_info.sync_next->thread_info.sync_prev = i;
2617 pa_sink_input_attach(i);
2619 pa_sink_input_set_state_within_thread(i, i->state);
2621 /* The requested latency of the sink input needs to be fixed up and
2622 * then configured on the sink. If this causes the sink latency to
2623 * go down, the sink implementor is responsible for doing a rewind
2624 * in the update_requested_latency() callback to ensure that the
2625 * sink buffer doesn't contain more data than what the new latency
2628 * XXX: Does it really make sense to push this responsibility to
2629 * the sink implementors? Wouldn't it be better to do it once in
2630 * the core than many times in the modules? */
2632 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
2633 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
2635 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
2636 pa_sink_input_update_max_request(i, s->thread_info.max_request);
2638 /* We don't rewind here automatically. This is left to the
2639 * sink input implementor because some sink inputs need a
2640 * slow start, i.e. need some time to buffer client
2641 * samples before beginning streaming.
2643 * XXX: Does it really make sense to push this functionality to
2644 * the sink implementors? Wouldn't it be better to do it once in
2645 * the core than many times in the modules? */
2647 /* In flat volume mode we need to update the volume as
2649 return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
2652 case PA_SINK_MESSAGE_REMOVE_INPUT: {
2653 pa_sink_input *i = PA_SINK_INPUT(userdata);
2655 /* If you change anything here, make sure to change the
2656 * sink input handling a few lines down at
2657 * PA_SINK_MESSAGE_START_MOVE, too. */
2659 pa_sink_input_detach(i);
2661 pa_sink_input_set_state_within_thread(i, i->state);
2663 /* Since the caller sleeps in pa_sink_input_unlink(),
2664 * we can safely access data outside of thread_info even
2665 * though it is mutable */
2667 pa_assert(!i->sync_prev);
2668 pa_assert(!i->sync_next);
2670 if (i->thread_info.sync_prev) {
2671 i->thread_info.sync_prev->thread_info.sync_next = i->thread_info.sync_prev->sync_next;
2672 i->thread_info.sync_prev = NULL;
2675 if (i->thread_info.sync_next) {
2676 i->thread_info.sync_next->thread_info.sync_prev = i->thread_info.sync_next->sync_prev;
2677 i->thread_info.sync_next = NULL;
2680 pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
2681 pa_sink_invalidate_requested_latency(s, true);
2682 pa_sink_request_rewind(s, (size_t) -1);
2684 /* In flat volume mode we need to update the volume as
2686 return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
2689 case PA_SINK_MESSAGE_START_MOVE: {
2690 pa_sink_input *i = PA_SINK_INPUT(userdata);
2692 /* We don't support moving synchronized streams. */
2693 pa_assert(!i->sync_prev);
2694 pa_assert(!i->sync_next);
2695 pa_assert(!i->thread_info.sync_next);
2696 pa_assert(!i->thread_info.sync_prev);
2698 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
2700 size_t sink_nbytes, total_nbytes;
2702 /* The old sink probably has some audio from this
2703 * stream in its buffer. We want to "take it back" as
2704 * much as possible and play it to the new sink. We
2705 * don't know at this point how much the old sink can
2706 * rewind. We have to pick something, and that
2707 * something is the full latency of the old sink here.
2708 * So we rewind the stream buffer by the sink latency
2709 * amount, which may be more than what we should
2710 * rewind. This can result in a chunk of audio being
2711 * played both to the old sink and the new sink.
2713 * FIXME: Fix this code so that we don't have to make
2714 * guesses about how much the sink will actually be
2715 * able to rewind. If someone comes up with a solution
2716 * for this, something to note is that the part of the
2717 * latency that the old sink couldn't rewind should
2718 * ideally be compensated after the stream has moved
2719 * to the new sink by adding silence. The new sink
2720 * most likely can't start playing the moved stream
2721 * immediately, and that gap should be removed from
2722 * the "compensation silence" (at least at the time of
2723 * writing this, the move finish code will actually
2724 * already take care of dropping the new sink's
2725 * unrewindable latency, so taking into account the
2726 * unrewindable latency of the old sink is the only
2729 * The render_memblockq contents are discarded,
2730 * because when the sink changes, the format of the
2731 * audio stored in the render_memblockq may change
2732 * too, making the stored audio invalid. FIXME:
2733 * However, the read and write indices are moved back
2734 * the same amount, so if they are not the same now,
2735 * they won't be the same after the rewind either. If
2736 * the write index of the render_memblockq is ahead of
2737 * the read index, then the render_memblockq will feed
2738 * the new sink some silence first, which it shouldn't
2739 * do. The write index should be flushed to be the
2740 * same as the read index. */
2742 /* Get the latency of the sink */
2743 usec = pa_sink_get_latency_within_thread(s, false);
2744 sink_nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
2745 total_nbytes = sink_nbytes + pa_memblockq_get_length(i->thread_info.render_memblockq);
2747 if (total_nbytes > 0) {
2748 i->thread_info.rewrite_nbytes = i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, total_nbytes) : total_nbytes;
2749 i->thread_info.rewrite_flush = true;
2750 pa_sink_input_process_rewind(i, sink_nbytes);
2754 pa_sink_input_detach(i);
2756 /* Let's remove the sink input ...*/
2757 pa_hashmap_remove_and_free(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index));
2759 pa_sink_invalidate_requested_latency(s, true);
2761 pa_log_debug("Requesting rewind due to started move");
2762 pa_sink_request_rewind(s, (size_t) -1);
2764 /* In flat volume mode we need to update the volume as
2766 return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
2769 case PA_SINK_MESSAGE_FINISH_MOVE: {
2770 pa_sink_input *i = PA_SINK_INPUT(userdata);
2772 /* We don't support moving synchronized streams. */
2773 pa_assert(!i->sync_prev);
2774 pa_assert(!i->sync_next);
2775 pa_assert(!i->thread_info.sync_next);
2776 pa_assert(!i->thread_info.sync_prev);
2778 pa_hashmap_put(s->thread_info.inputs, PA_UINT32_TO_PTR(i->index), pa_sink_input_ref(i));
2780 pa_sink_input_attach(i);
2782 if (i->thread_info.state != PA_SINK_INPUT_CORKED) {
2786 /* In the ideal case the new sink would start playing
2787 * the stream immediately. That requires the sink to
2788 * be able to rewind all of its latency, which usually
2789 * isn't possible, so there will probably be some gap
2790 * before the moved stream becomes audible. We then
2791 * have two possibilities: 1) start playing the stream
2792 * from where it is now, or 2) drop the unrewindable
2793 * latency of the sink from the stream. With option 1
2794 * we won't lose any audio but the stream will have a
2795 * pause. With option 2 we may lose some audio but the
2796 * stream time will be somewhat in sync with the wall
2797 * clock. Lennart seems to have chosen option 2 (one
2798 * of the reasons might have been that option 1 is
2799 * actually much harder to implement), so we drop the
2800 * latency of the new sink from the moved stream and
2801 * hope that the sink will undo most of that in the
2804 /* Get the latency of the sink */
2805 usec = pa_sink_get_latency_within_thread(s, false);
2806 nbytes = pa_usec_to_bytes(usec, &s->sample_spec);
2809 pa_sink_input_drop(i, nbytes);
2811 pa_log_debug("Requesting rewind due to finished move");
2812 pa_sink_request_rewind(s, nbytes);
2815 /* Updating the requested sink latency has to be done
2816 * after the sink rewind request, not before, because
2817 * otherwise the sink may limit the rewind amount
2820 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1)
2821 pa_sink_input_set_requested_latency_within_thread(i, i->thread_info.requested_sink_latency);
2823 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
2824 pa_sink_input_update_max_request(i, s->thread_info.max_request);
2826 return o->process_msg(o, PA_SINK_MESSAGE_SET_SHARED_VOLUME, NULL, 0, NULL);
2829 case PA_SINK_MESSAGE_SET_SHARED_VOLUME: {
2830 pa_sink *root_sink = pa_sink_get_master(s);
2832 if (PA_LIKELY(root_sink))
2833 set_shared_volume_within_thread(root_sink);
2838 case PA_SINK_MESSAGE_SET_VOLUME_SYNCED:
2840 if (s->flags & PA_SINK_DEFERRED_VOLUME) {
2842 pa_sink_volume_change_push(s);
2844 /* Fall through ... */
2846 case PA_SINK_MESSAGE_SET_VOLUME:
2848 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
2849 s->thread_info.soft_volume = s->soft_volume;
2850 pa_sink_request_rewind(s, (size_t) -1);
2853 /* Fall through ... */
2855 case PA_SINK_MESSAGE_SYNC_VOLUMES:
2856 sync_input_volumes_within_thread(s);
2859 case PA_SINK_MESSAGE_GET_VOLUME:
2861 if ((s->flags & PA_SINK_DEFERRED_VOLUME) && s->get_volume) {
2863 pa_sink_volume_change_flush(s);
2864 pa_sw_cvolume_divide(&s->thread_info.current_hw_volume, &s->real_volume, &s->soft_volume);
2867 /* In case sink implementor reset SW volume. */
2868 if (!pa_cvolume_equal(&s->thread_info.soft_volume, &s->soft_volume)) {
2869 s->thread_info.soft_volume = s->soft_volume;
2870 pa_sink_request_rewind(s, (size_t) -1);
2875 case PA_SINK_MESSAGE_SET_MUTE:
2877 if (s->thread_info.soft_muted != s->muted) {
2878 s->thread_info.soft_muted = s->muted;
2879 pa_sink_request_rewind(s, (size_t) -1);
2882 if (s->flags & PA_SINK_DEFERRED_VOLUME && s->set_mute)
2887 case PA_SINK_MESSAGE_GET_MUTE:
2889 if (s->flags & PA_SINK_DEFERRED_VOLUME && s->get_mute)
2890 return s->get_mute(s, userdata);
2894 case PA_SINK_MESSAGE_SET_STATE: {
2896 bool suspend_change =
2897 (s->thread_info.state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(PA_PTR_TO_UINT(userdata))) ||
2898 (PA_SINK_IS_OPENED(s->thread_info.state) && PA_PTR_TO_UINT(userdata) == PA_SINK_SUSPENDED);
2900 s->thread_info.state = PA_PTR_TO_UINT(userdata);
2902 if (s->thread_info.state == PA_SINK_SUSPENDED) {
2903 s->thread_info.rewind_nbytes = 0;
2904 s->thread_info.rewind_requested = false;
2907 if (suspend_change) {
2911 while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)))
2912 if (i->suspend_within_thread)
2913 i->suspend_within_thread(i, s->thread_info.state == PA_SINK_SUSPENDED);
2919 case PA_SINK_MESSAGE_GET_REQUESTED_LATENCY: {
2921 pa_usec_t *usec = userdata;
2922 *usec = pa_sink_get_requested_latency_within_thread(s);
2924 /* Yes, that's right, the IO thread will see -1 when no
2925 * explicit requested latency is configured, the main
2926 * thread will see max_latency */
2927 if (*usec == (pa_usec_t) -1)
2928 *usec = s->thread_info.max_latency;
2933 case PA_SINK_MESSAGE_SET_LATENCY_RANGE: {
2934 pa_usec_t *r = userdata;
2936 pa_sink_set_latency_range_within_thread(s, r[0], r[1]);
2941 case PA_SINK_MESSAGE_GET_LATENCY_RANGE: {
2942 pa_usec_t *r = userdata;
2944 r[0] = s->thread_info.min_latency;
2945 r[1] = s->thread_info.max_latency;
2950 case PA_SINK_MESSAGE_GET_FIXED_LATENCY:
2952 *((pa_usec_t*) userdata) = s->thread_info.fixed_latency;
2955 case PA_SINK_MESSAGE_SET_FIXED_LATENCY:
2957 pa_sink_set_fixed_latency_within_thread(s, (pa_usec_t) offset);
2960 case PA_SINK_MESSAGE_GET_MAX_REWIND:
2962 *((size_t*) userdata) = s->thread_info.max_rewind;
2965 case PA_SINK_MESSAGE_GET_MAX_REQUEST:
2967 *((size_t*) userdata) = s->thread_info.max_request;
2970 case PA_SINK_MESSAGE_SET_MAX_REWIND:
2972 pa_sink_set_max_rewind_within_thread(s, (size_t) offset);
2975 case PA_SINK_MESSAGE_SET_MAX_REQUEST:
2977 pa_sink_set_max_request_within_thread(s, (size_t) offset);
2980 case PA_SINK_MESSAGE_SET_PORT:
2982 pa_assert(userdata);
2984 struct sink_message_set_port *msg_data = userdata;
2985 msg_data->ret = s->set_port(s, msg_data->port);
2989 case PA_SINK_MESSAGE_UPDATE_VOLUME_AND_MUTE:
2990 /* This message is sent from IO-thread and handled in main thread. */
2991 pa_assert_ctl_context();
2993 /* Make sure we're not messing with main thread when no longer linked */
2994 if (!PA_SINK_IS_LINKED(s->state))
2997 pa_sink_get_volume(s, true);
2998 pa_sink_get_mute(s, true);
3001 case PA_SINK_MESSAGE_SET_PORT_LATENCY_OFFSET:
3002 s->thread_info.port_latency_offset = offset;
3005 case PA_SINK_MESSAGE_GET_LATENCY:
3006 case PA_SINK_MESSAGE_MAX:
3013 /* Called from main thread */
3014 int pa_sink_suspend_all(pa_core *c, bool suspend, pa_suspend_cause_t cause) {
3019 pa_core_assert_ref(c);
3020 pa_assert_ctl_context();
3021 pa_assert(cause != 0);
3023 PA_IDXSET_FOREACH(sink, c->sinks, idx) {
3026 if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
3033 /* Called from IO thread */
3034 void pa_sink_detach_within_thread(pa_sink *s) {
3038 pa_sink_assert_ref(s);
3039 pa_sink_assert_io_context(s);
3040 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
3042 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3043 pa_sink_input_detach(i);
3045 if (s->monitor_source)
3046 pa_source_detach_within_thread(s->monitor_source);
3049 /* Called from IO thread */
3050 void pa_sink_attach_within_thread(pa_sink *s) {
3054 pa_sink_assert_ref(s);
3055 pa_sink_assert_io_context(s);
3056 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
3058 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3059 pa_sink_input_attach(i);
3061 if (s->monitor_source)
3062 pa_source_attach_within_thread(s->monitor_source);
3065 /* Called from IO thread */
3066 void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
3067 pa_sink_assert_ref(s);
3068 pa_sink_assert_io_context(s);
3069 pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
3071 if (nbytes == (size_t) -1)
3072 nbytes = s->thread_info.max_rewind;
3074 nbytes = PA_MIN(nbytes, s->thread_info.max_rewind);
3076 if (s->thread_info.rewind_requested &&
3077 nbytes <= s->thread_info.rewind_nbytes)
3080 s->thread_info.rewind_nbytes = nbytes;
3081 s->thread_info.rewind_requested = true;
3083 if (s->request_rewind)
3084 s->request_rewind(s);
3087 /* Called from IO thread */
3088 pa_usec_t pa_sink_get_requested_latency_within_thread(pa_sink *s) {
3089 pa_usec_t result = (pa_usec_t) -1;
3092 pa_usec_t monitor_latency;
3094 pa_sink_assert_ref(s);
3095 pa_sink_assert_io_context(s);
3097 if (!(s->flags & PA_SINK_DYNAMIC_LATENCY))
3098 return PA_CLAMP(s->thread_info.fixed_latency, s->thread_info.min_latency, s->thread_info.max_latency);
3100 if (s->thread_info.requested_latency_valid)
3101 return s->thread_info.requested_latency;
3103 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3104 if (i->thread_info.requested_sink_latency != (pa_usec_t) -1 &&
3105 (result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
3106 result = i->thread_info.requested_sink_latency;
3108 monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
3110 if (monitor_latency != (pa_usec_t) -1 &&
3111 (result == (pa_usec_t) -1 || result > monitor_latency))
3112 result = monitor_latency;
3114 if (result != (pa_usec_t) -1)
3115 result = PA_CLAMP(result, s->thread_info.min_latency, s->thread_info.max_latency);
3117 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
3118 /* Only cache if properly initialized */
3119 s->thread_info.requested_latency = result;
3120 s->thread_info.requested_latency_valid = true;
3126 /* Called from main thread */
3127 pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
3130 pa_sink_assert_ref(s);
3131 pa_assert_ctl_context();
3132 pa_assert(PA_SINK_IS_LINKED(s->state));
3134 if (s->state == PA_SINK_SUSPENDED)
3137 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
3142 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
3143 void pa_sink_set_max_rewind_within_thread(pa_sink *s, size_t max_rewind) {
3147 pa_sink_assert_ref(s);
3148 pa_sink_assert_io_context(s);
3150 if (max_rewind == s->thread_info.max_rewind)
3153 s->thread_info.max_rewind = max_rewind;
3155 if (PA_SINK_IS_LINKED(s->thread_info.state))
3156 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3157 pa_sink_input_update_max_rewind(i, s->thread_info.max_rewind);
3159 if (s->monitor_source)
3160 pa_source_set_max_rewind_within_thread(s->monitor_source, s->thread_info.max_rewind);
3163 /* Called from main thread */
3164 void pa_sink_set_max_rewind(pa_sink *s, size_t max_rewind) {
3165 pa_sink_assert_ref(s);
3166 pa_assert_ctl_context();
3168 if (PA_SINK_IS_LINKED(s->state))
3169 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REWIND, NULL, max_rewind, NULL) == 0);
3171 pa_sink_set_max_rewind_within_thread(s, max_rewind);
3174 /* Called from IO as well as the main thread -- the latter only before the IO thread started up */
3175 void pa_sink_set_max_request_within_thread(pa_sink *s, size_t max_request) {
3178 pa_sink_assert_ref(s);
3179 pa_sink_assert_io_context(s);
3181 if (max_request == s->thread_info.max_request)
3184 s->thread_info.max_request = max_request;
3186 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
3189 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3190 pa_sink_input_update_max_request(i, s->thread_info.max_request);
3194 /* Called from main thread */
3195 void pa_sink_set_max_request(pa_sink *s, size_t max_request) {
3196 pa_sink_assert_ref(s);
3197 pa_assert_ctl_context();
3199 if (PA_SINK_IS_LINKED(s->state))
3200 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MAX_REQUEST, NULL, max_request, NULL) == 0);
3202 pa_sink_set_max_request_within_thread(s, max_request);
3205 /* Called from IO thread */
3206 void pa_sink_invalidate_requested_latency(pa_sink *s, bool dynamic) {
3210 pa_sink_assert_ref(s);
3211 pa_sink_assert_io_context(s);
3213 if ((s->flags & PA_SINK_DYNAMIC_LATENCY))
3214 s->thread_info.requested_latency_valid = false;
3218 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
3220 if (s->update_requested_latency)
3221 s->update_requested_latency(s);
3223 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3224 if (i->update_sink_requested_latency)
3225 i->update_sink_requested_latency(i);
3229 /* Called from main thread */
3230 void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
3231 pa_sink_assert_ref(s);
3232 pa_assert_ctl_context();
3234 /* min_latency == 0: no limit
3235 * min_latency anything else: specified limit
3237 * Similar for max_latency */
3239 if (min_latency < ABSOLUTE_MIN_LATENCY)
3240 min_latency = ABSOLUTE_MIN_LATENCY;
3242 if (max_latency <= 0 ||
3243 max_latency > ABSOLUTE_MAX_LATENCY)
3244 max_latency = ABSOLUTE_MAX_LATENCY;
3246 pa_assert(min_latency <= max_latency);
3248 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
3249 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
3250 max_latency == ABSOLUTE_MAX_LATENCY) ||
3251 (s->flags & PA_SINK_DYNAMIC_LATENCY));
3253 if (PA_SINK_IS_LINKED(s->state)) {
3259 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_LATENCY_RANGE, r, 0, NULL) == 0);
3261 pa_sink_set_latency_range_within_thread(s, min_latency, max_latency);
3264 /* Called from main thread */
3265 void pa_sink_get_latency_range(pa_sink *s, pa_usec_t *min_latency, pa_usec_t *max_latency) {
3266 pa_sink_assert_ref(s);
3267 pa_assert_ctl_context();
3268 pa_assert(min_latency);
3269 pa_assert(max_latency);
3271 if (PA_SINK_IS_LINKED(s->state)) {
3272 pa_usec_t r[2] = { 0, 0 };
3274 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_LATENCY_RANGE, r, 0, NULL) == 0);
3276 *min_latency = r[0];
3277 *max_latency = r[1];
3279 *min_latency = s->thread_info.min_latency;
3280 *max_latency = s->thread_info.max_latency;
3284 /* Called from IO thread */
3285 void pa_sink_set_latency_range_within_thread(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
3286 pa_sink_assert_ref(s);
3287 pa_sink_assert_io_context(s);
3289 pa_assert(min_latency >= ABSOLUTE_MIN_LATENCY);
3290 pa_assert(max_latency <= ABSOLUTE_MAX_LATENCY);
3291 pa_assert(min_latency <= max_latency);
3293 /* Hmm, let's see if someone forgot to set PA_SINK_DYNAMIC_LATENCY here... */
3294 pa_assert((min_latency == ABSOLUTE_MIN_LATENCY &&
3295 max_latency == ABSOLUTE_MAX_LATENCY) ||
3296 (s->flags & PA_SINK_DYNAMIC_LATENCY));
3298 if (s->thread_info.min_latency == min_latency &&
3299 s->thread_info.max_latency == max_latency)
3302 s->thread_info.min_latency = min_latency;
3303 s->thread_info.max_latency = max_latency;
3305 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
3309 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3310 if (i->update_sink_latency_range)
3311 i->update_sink_latency_range(i);
3314 pa_sink_invalidate_requested_latency(s, false);
3316 pa_source_set_latency_range_within_thread(s->monitor_source, min_latency, max_latency);
3319 /* Called from main thread */
3320 void pa_sink_set_fixed_latency(pa_sink *s, pa_usec_t latency) {
3321 pa_sink_assert_ref(s);
3322 pa_assert_ctl_context();
3324 if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
3325 pa_assert(latency == 0);
3329 if (latency < ABSOLUTE_MIN_LATENCY)
3330 latency = ABSOLUTE_MIN_LATENCY;
3332 if (latency > ABSOLUTE_MAX_LATENCY)
3333 latency = ABSOLUTE_MAX_LATENCY;
3335 if (PA_SINK_IS_LINKED(s->state))
3336 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_FIXED_LATENCY, NULL, (int64_t) latency, NULL) == 0);
3338 s->thread_info.fixed_latency = latency;
3340 pa_source_set_fixed_latency(s->monitor_source, latency);
3343 /* Called from main thread */
3344 pa_usec_t pa_sink_get_fixed_latency(pa_sink *s) {
3347 pa_sink_assert_ref(s);
3348 pa_assert_ctl_context();
3350 if (s->flags & PA_SINK_DYNAMIC_LATENCY)
3353 if (PA_SINK_IS_LINKED(s->state))
3354 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_FIXED_LATENCY, &latency, 0, NULL) == 0);
3356 latency = s->thread_info.fixed_latency;
3361 /* Called from IO thread */
3362 void pa_sink_set_fixed_latency_within_thread(pa_sink *s, pa_usec_t latency) {
3363 pa_sink_assert_ref(s);
3364 pa_sink_assert_io_context(s);
3366 if (s->flags & PA_SINK_DYNAMIC_LATENCY) {
3367 pa_assert(latency == 0);
3368 s->thread_info.fixed_latency = 0;
3370 if (s->monitor_source)
3371 pa_source_set_fixed_latency_within_thread(s->monitor_source, 0);
3376 pa_assert(latency >= ABSOLUTE_MIN_LATENCY);
3377 pa_assert(latency <= ABSOLUTE_MAX_LATENCY);
3379 if (s->thread_info.fixed_latency == latency)
3382 s->thread_info.fixed_latency = latency;
3384 if (PA_SINK_IS_LINKED(s->thread_info.state)) {
3388 PA_HASHMAP_FOREACH(i, s->thread_info.inputs, state)
3389 if (i->update_sink_fixed_latency)
3390 i->update_sink_fixed_latency(i);
3393 pa_sink_invalidate_requested_latency(s, false);
3395 pa_source_set_fixed_latency_within_thread(s->monitor_source, latency);
3398 /* Called from main context */
3399 void pa_sink_set_port_latency_offset(pa_sink *s, int64_t offset) {
3400 pa_sink_assert_ref(s);
3402 s->port_latency_offset = offset;
3404 if (PA_SINK_IS_LINKED(s->state))
3405 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT_LATENCY_OFFSET, NULL, offset, NULL) == 0);
3407 s->thread_info.port_latency_offset = offset;
3409 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_LATENCY_OFFSET_CHANGED], s);
3412 /* Called from main context */
3413 size_t pa_sink_get_max_rewind(pa_sink *s) {
3415 pa_assert_ctl_context();
3416 pa_sink_assert_ref(s);
3418 if (!PA_SINK_IS_LINKED(s->state))
3419 return s->thread_info.max_rewind;
3421 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REWIND, &r, 0, NULL) == 0);
3426 /* Called from main context */
3427 size_t pa_sink_get_max_request(pa_sink *s) {
3429 pa_sink_assert_ref(s);
3430 pa_assert_ctl_context();
3432 if (!PA_SINK_IS_LINKED(s->state))
3433 return s->thread_info.max_request;
3435 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MAX_REQUEST, &r, 0, NULL) == 0);
3440 /* Called from main context */
3441 int pa_sink_set_port(pa_sink *s, const char *name, bool save) {
3442 pa_device_port *port;
3445 pa_sink_assert_ref(s);
3446 pa_assert_ctl_context();
3449 pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
3450 return -PA_ERR_NOTIMPLEMENTED;
3454 return -PA_ERR_NOENTITY;
3456 if (!(port = pa_hashmap_get(s->ports, name)))
3457 return -PA_ERR_NOENTITY;
3459 if (s->active_port == port) {
3460 s->save_port = s->save_port || save;
3464 if (s->flags & PA_SINK_DEFERRED_VOLUME) {
3465 struct sink_message_set_port msg = { .port = port, .ret = 0 };
3466 pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_PORT, &msg, 0, NULL) == 0);
3470 ret = s->set_port(s, port);
3473 return -PA_ERR_NOENTITY;
3475 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
3477 pa_log_info("Changed port of sink %u \"%s\" to %s", s->index, s->name, port->name);
3479 s->active_port = port;
3480 s->save_port = save;
3482 pa_sink_set_port_latency_offset(s, s->active_port->latency_offset);
3484 /* The active port affects the default sink selection. */
3485 pa_core_update_default_sink(s->core);
3487 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_PORT_CHANGED], s);
3492 bool pa_device_init_icon(pa_proplist *p, bool is_sink) {
3493 const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
3497 if (pa_proplist_contains(p, PA_PROP_DEVICE_ICON_NAME))
3500 if ((ff = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
3502 if (pa_streq(ff, "microphone"))
3503 t = "audio-input-microphone";
3504 else if (pa_streq(ff, "webcam"))
3506 else if (pa_streq(ff, "computer"))
3508 else if (pa_streq(ff, "handset"))
3510 else if (pa_streq(ff, "portable"))
3511 t = "multimedia-player";
3512 else if (pa_streq(ff, "tv"))
3513 t = "video-display";
3516 * The following icons are not part of the icon naming spec,
3517 * because Rodney Dawes sucks as the maintainer of that spec.
3519 * http://lists.freedesktop.org/archives/xdg/2009-May/010397.html
3521 else if (pa_streq(ff, "headset"))
3522 t = "audio-headset";
3523 else if (pa_streq(ff, "headphone"))
3524 t = "audio-headphones";
3525 else if (pa_streq(ff, "speaker"))
3526 t = "audio-speakers";
3527 else if (pa_streq(ff, "hands-free"))
3528 t = "audio-handsfree";
3532 if ((c = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
3533 if (pa_streq(c, "modem"))
3540 t = "audio-input-microphone";
3543 if ((profile = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
3544 if (strstr(profile, "analog"))
3546 else if (strstr(profile, "iec958"))
3548 else if (strstr(profile, "hdmi"))
3552 bus = pa_proplist_gets(p, PA_PROP_DEVICE_BUS);
3554 pa_proplist_setf(p, PA_PROP_DEVICE_ICON_NAME, "%s%s%s%s", t, pa_strempty(s), bus ? "-" : "", pa_strempty(bus));
3559 bool pa_device_init_description(pa_proplist *p, pa_card *card) {
3560 const char *s, *d = NULL, *k;
3563 if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
3567 if ((s = pa_proplist_gets(card->proplist, PA_PROP_DEVICE_DESCRIPTION)))
3571 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
3572 if (pa_streq(s, "internal"))
3573 d = _("Built-in Audio");
3576 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
3577 if (pa_streq(s, "modem"))
3581 d = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME);
3586 k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
3589 pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, "%s %s", d, k);
3591 pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
3596 bool pa_device_init_intended_roles(pa_proplist *p) {
3600 if (pa_proplist_contains(p, PA_PROP_DEVICE_INTENDED_ROLES))
3603 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
3604 if (pa_streq(s, "handset") || pa_streq(s, "hands-free")
3605 || pa_streq(s, "headset")) {
3606 pa_proplist_sets(p, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
3613 unsigned pa_device_init_priority(pa_proplist *p) {
3615 unsigned priority = 0;
3619 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS))) {
3621 if (pa_streq(s, "sound"))
3623 else if (!pa_streq(s, "modem"))
3627 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR))) {
3629 if (pa_streq(s, "headphone"))
3631 else if (pa_streq(s, "hifi"))
3633 else if (pa_streq(s, "speaker"))
3635 else if (pa_streq(s, "portable"))
3639 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_BUS))) {
3641 if (pa_streq(s, "bluetooth"))
3643 else if (pa_streq(s, "usb"))
3645 else if (pa_streq(s, "pci"))
3649 if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_NAME))) {
3651 if (pa_startswith(s, "analog-"))
3653 else if (pa_startswith(s, "iec958-"))
3660 PA_STATIC_FLIST_DECLARE(pa_sink_volume_change, 0, pa_xfree);
3662 /* Called from the IO thread. */
3663 static pa_sink_volume_change *pa_sink_volume_change_new(pa_sink *s) {
3664 pa_sink_volume_change *c;
3665 if (!(c = pa_flist_pop(PA_STATIC_FLIST_GET(pa_sink_volume_change))))
3666 c = pa_xnew(pa_sink_volume_change, 1);
3668 PA_LLIST_INIT(pa_sink_volume_change, c);
3670 pa_cvolume_reset(&c->hw_volume, s->sample_spec.channels);
3674 /* Called from the IO thread. */
3675 static void pa_sink_volume_change_free(pa_sink_volume_change *c) {
3677 if (pa_flist_push(PA_STATIC_FLIST_GET(pa_sink_volume_change), c) < 0)
3681 /* Called from the IO thread. */
3682 void pa_sink_volume_change_push(pa_sink *s) {
3683 pa_sink_volume_change *c = NULL;
3684 pa_sink_volume_change *nc = NULL;
3685 pa_sink_volume_change *pc = NULL;
3686 uint32_t safety_margin = s->thread_info.volume_change_safety_margin;
3688 const char *direction = NULL;
3691 nc = pa_sink_volume_change_new(s);
3693 /* NOTE: There is already more different volumes in pa_sink that I can remember.
3694 * Adding one more volume for HW would get us rid of this, but I am trying
3695 * to survive with the ones we already have. */
3696 pa_sw_cvolume_divide(&nc->hw_volume, &s->real_volume, &s->soft_volume);
3698 if (!s->thread_info.volume_changes && pa_cvolume_equal(&nc->hw_volume, &s->thread_info.current_hw_volume)) {
3699 pa_log_debug("Volume not changing");
3700 pa_sink_volume_change_free(nc);
3704 nc->at = pa_sink_get_latency_within_thread(s, false);
3705 nc->at += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
3707 if (s->thread_info.volume_changes_tail) {
3708 for (c = s->thread_info.volume_changes_tail; c; c = c->prev) {
3709 /* If volume is going up let's do it a bit late. If it is going
3710 * down let's do it a bit early. */
3711 if (pa_cvolume_avg(&nc->hw_volume) > pa_cvolume_avg(&c->hw_volume)) {
3712 if (nc->at + safety_margin > c->at) {
3713 nc->at += safety_margin;
3718 else if (nc->at - safety_margin > c->at) {
3719 nc->at -= safety_margin;
3727 if (pa_cvolume_avg(&nc->hw_volume) > pa_cvolume_avg(&s->thread_info.current_hw_volume)) {
3728 nc->at += safety_margin;
3731 nc->at -= safety_margin;
3734 PA_LLIST_PREPEND(pa_sink_volume_change, s->thread_info.volume_changes, nc);
3737 PA_LLIST_INSERT_AFTER(pa_sink_volume_change, s->thread_info.volume_changes, c, nc);
3740 pa_log_debug("Volume going %s to %d at %llu", direction, pa_cvolume_avg(&nc->hw_volume), (long long unsigned) nc->at);
3742 /* We can ignore volume events that came earlier but should happen later than this. */
3743 PA_LLIST_FOREACH_SAFE(c, pc, nc->next) {
3744 pa_log_debug("Volume change to %d at %llu was dropped", pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at);
3745 pa_sink_volume_change_free(c);
3748 s->thread_info.volume_changes_tail = nc;
3751 /* Called from the IO thread. */
3752 static void pa_sink_volume_change_flush(pa_sink *s) {
3753 pa_sink_volume_change *c = s->thread_info.volume_changes;
3755 s->thread_info.volume_changes = NULL;
3756 s->thread_info.volume_changes_tail = NULL;
3758 pa_sink_volume_change *next = c->next;
3759 pa_sink_volume_change_free(c);
3764 /* Called from the IO thread. */
3765 bool pa_sink_volume_change_apply(pa_sink *s, pa_usec_t *usec_to_next) {
3771 if (!s->thread_info.volume_changes || !PA_SINK_IS_LINKED(s->state)) {
3777 pa_assert(s->write_volume);
3779 now = pa_rtclock_now();
3781 while (s->thread_info.volume_changes && now >= s->thread_info.volume_changes->at) {
3782 pa_sink_volume_change *c = s->thread_info.volume_changes;
3783 PA_LLIST_REMOVE(pa_sink_volume_change, s->thread_info.volume_changes, c);
3784 pa_log_debug("Volume change to %d at %llu was written %llu usec late",
3785 pa_cvolume_avg(&c->hw_volume), (long long unsigned) c->at, (long long unsigned) (now - c->at));
3787 s->thread_info.current_hw_volume = c->hw_volume;
3788 pa_sink_volume_change_free(c);
3794 if (s->thread_info.volume_changes) {
3796 *usec_to_next = s->thread_info.volume_changes->at - now;
3797 if (pa_log_ratelimit(PA_LOG_DEBUG))
3798 pa_log_debug("Next volume change in %lld usec", (long long) (s->thread_info.volume_changes->at - now));
3803 s->thread_info.volume_changes_tail = NULL;
3808 /* Called from the IO thread. */
3809 static void pa_sink_volume_change_rewind(pa_sink *s, size_t nbytes) {
3810 /* All the queued volume events later than current latency are shifted to happen earlier. */
3811 pa_sink_volume_change *c;
3812 pa_volume_t prev_vol = pa_cvolume_avg(&s->thread_info.current_hw_volume);
3813 pa_usec_t rewound = pa_bytes_to_usec(nbytes, &s->sample_spec);
3814 pa_usec_t limit = pa_sink_get_latency_within_thread(s, false);
3816 pa_log_debug("latency = %lld", (long long) limit);
3817 limit += pa_rtclock_now() + s->thread_info.volume_change_extra_delay;
3819 PA_LLIST_FOREACH(c, s->thread_info.volume_changes) {
3820 pa_usec_t modified_limit = limit;
3821 if (prev_vol > pa_cvolume_avg(&c->hw_volume))
3822 modified_limit -= s->thread_info.volume_change_safety_margin;
3824 modified_limit += s->thread_info.volume_change_safety_margin;
3825 if (c->at > modified_limit) {
3827 if (c->at < modified_limit)
3828 c->at = modified_limit;
3830 prev_vol = pa_cvolume_avg(&c->hw_volume);
3832 pa_sink_volume_change_apply(s, NULL);
3835 /* Called from the main thread */
3836 /* Gets the list of formats supported by the sink. The members and idxset must
3837 * be freed by the caller. */
3838 pa_idxset* pa_sink_get_formats(pa_sink *s) {
3843 if (s->get_formats) {
3844 /* Sink supports format query, all is good */
3845 ret = s->get_formats(s);
3847 /* Sink doesn't support format query, so assume it does PCM */
3848 pa_format_info *f = pa_format_info_new();
3849 f->encoding = PA_ENCODING_PCM;
3851 ret = pa_idxset_new(NULL, NULL);
3852 pa_idxset_put(ret, f, NULL);
3858 /* Called from the main thread */
3859 /* Allows an external source to set what formats a sink supports if the sink
3860 * permits this. The function makes a copy of the formats on success. */
3861 bool pa_sink_set_formats(pa_sink *s, pa_idxset *formats) {
3866 /* Sink supports setting formats -- let's give it a shot */
3867 return s->set_formats(s, formats);
3869 /* Sink doesn't support setting this -- bail out */
3873 /* Called from the main thread */
3874 /* Checks if the sink can accept this format */
3875 bool pa_sink_check_format(pa_sink *s, pa_format_info *f) {
3876 pa_idxset *formats = NULL;
3882 formats = pa_sink_get_formats(s);
3885 pa_format_info *finfo_device;
3888 PA_IDXSET_FOREACH(finfo_device, formats, i) {
3889 if (pa_format_info_is_compatible(finfo_device, f)) {
3895 pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
3901 /* Called from the main thread */
3902 /* Calculates the intersection between formats supported by the sink and
3903 * in_formats, and returns these, in the order of the sink's formats. */
3904 pa_idxset* pa_sink_check_formats(pa_sink *s, pa_idxset *in_formats) {
3905 pa_idxset *out_formats = pa_idxset_new(NULL, NULL), *sink_formats = NULL;
3906 pa_format_info *f_sink, *f_in;
3911 if (!in_formats || pa_idxset_isempty(in_formats))
3914 sink_formats = pa_sink_get_formats(s);
3916 PA_IDXSET_FOREACH(f_sink, sink_formats, i) {
3917 PA_IDXSET_FOREACH(f_in, in_formats, j) {
3918 if (pa_format_info_is_compatible(f_sink, f_in))
3919 pa_idxset_put(out_formats, pa_format_info_copy(f_in), NULL);
3925 pa_idxset_free(sink_formats, (pa_free_cb_t) pa_format_info_free);
3930 /* Called from the main thread. */
3931 void pa_sink_set_reference_volume_direct(pa_sink *s, const pa_cvolume *volume) {
3932 pa_cvolume old_volume;
3933 char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
3934 char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
3939 old_volume = s->reference_volume;
3941 if (pa_cvolume_equal(volume, &old_volume))
3944 s->reference_volume = *volume;
3945 pa_log_debug("The reference volume of sink %s changed from %s to %s.", s->name,
3946 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &s->channel_map,
3947 s->flags & PA_SINK_DECIBEL_VOLUME),
3948 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &s->channel_map,
3949 s->flags & PA_SINK_DECIBEL_VOLUME));
3951 pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
3952 pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_VOLUME_CHANGED], s);