153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
953a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1053a5a1b3Sopenharmony_ci  or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1853a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <stdio.h>
2653a5a1b3Sopenharmony_ci#include <stdlib.h>
2753a5a1b3Sopenharmony_ci
2853a5a1b3Sopenharmony_ci#include <pulse/utf8.h>
2953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3053a5a1b3Sopenharmony_ci#include <pulse/util.h>
3153a5a1b3Sopenharmony_ci#include <pulse/internal.h>
3253a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
3353a5a1b3Sopenharmony_ci
3453a5a1b3Sopenharmony_ci#include <pulsecore/core-format.h>
3553a5a1b3Sopenharmony_ci#include <pulsecore/mix.h>
3653a5a1b3Sopenharmony_ci#include <pulsecore/stream-util.h>
3753a5a1b3Sopenharmony_ci#include <pulsecore/core-subscribe.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3953a5a1b3Sopenharmony_ci#include <pulsecore/play-memblockq.h>
4053a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h>
4153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
4253a5a1b3Sopenharmony_ci
4353a5a1b3Sopenharmony_ci#include "sink-input.h"
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_ci/* #define SINK_INPUT_DEBUG */
4653a5a1b3Sopenharmony_ci
4753a5a1b3Sopenharmony_ci#define MEMBLOCKQ_MAXLENGTH (32*1024*1024)
4853a5a1b3Sopenharmony_ci#define CONVERT_BUFFER_LENGTH (pa_page_size())
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ciPA_DEFINE_PUBLIC_CLASS(pa_sink_input, pa_msgobject);
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_cistruct volume_factor_entry {
5353a5a1b3Sopenharmony_ci    char *key;
5453a5a1b3Sopenharmony_ci    pa_cvolume volume;
5553a5a1b3Sopenharmony_ci};
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_ci/* Calculate number of input samples for the resampler so that either the number
5853a5a1b3Sopenharmony_ci * of input samples or the number of output samples matches the defined history
5953a5a1b3Sopenharmony_ci * length. */
6053a5a1b3Sopenharmony_cistatic size_t calculate_resampler_history_bytes(pa_sink_input *i, size_t in_rewind_frames) {
6153a5a1b3Sopenharmony_ci    size_t history_frames, history_max, matching_period, total_frames, remainder;
6253a5a1b3Sopenharmony_ci    double delay;
6353a5a1b3Sopenharmony_ci    pa_resampler *r;
6453a5a1b3Sopenharmony_ci
6553a5a1b3Sopenharmony_ci    if (!(r = i->thread_info.resampler))
6653a5a1b3Sopenharmony_ci        return 0;
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_ci    /* Initialize some variables, cut off full seconds from the rewind */
6953a5a1b3Sopenharmony_ci    total_frames = 0;
7053a5a1b3Sopenharmony_ci    in_rewind_frames = in_rewind_frames % r->i_ss.rate;
7153a5a1b3Sopenharmony_ci    history_max = pa_resampler_get_max_history(r);
7253a5a1b3Sopenharmony_ci
7353a5a1b3Sopenharmony_ci    /* Get the current internal delay of the resampler */
7453a5a1b3Sopenharmony_ci    delay = pa_resampler_get_delay(r, false);
7553a5a1b3Sopenharmony_ci
7653a5a1b3Sopenharmony_ci    /* Calculate the matching period */
7753a5a1b3Sopenharmony_ci    matching_period = r->i_ss.rate / pa_resampler_get_gcd(r);
7853a5a1b3Sopenharmony_ci    pa_log_debug("Integral period length is %zu input frames", matching_period);
7953a5a1b3Sopenharmony_ci
8053a5a1b3Sopenharmony_ci    /* If the delay is larger than the length of the history queue, we can only
8153a5a1b3Sopenharmony_ci     * replay as much as we have. */
8253a5a1b3Sopenharmony_ci    if ((size_t)delay >= history_max) {
8353a5a1b3Sopenharmony_ci        history_frames = history_max;
8453a5a1b3Sopenharmony_ci        pa_log_debug("Resampler delay exceeds maximum history");
8553a5a1b3Sopenharmony_ci        return history_frames * r->i_fz;
8653a5a1b3Sopenharmony_ci    }
8753a5a1b3Sopenharmony_ci
8853a5a1b3Sopenharmony_ci    /* Initially set the history to 3 times the resampler delay. Use at least 2 ms.
8953a5a1b3Sopenharmony_ci     * We try to find a value between 2 and 3 times the resampler delay to ensure
9053a5a1b3Sopenharmony_ci     * that the old data has no impact anymore. See also comment to
9153a5a1b3Sopenharmony_ci     * pa_resampler_get_max_history() in resampler.c. */
9253a5a1b3Sopenharmony_ci    history_frames = (size_t)(delay * 3.0);
9353a5a1b3Sopenharmony_ci    history_frames = PA_MAX(history_frames, r->i_ss.rate / 500);
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_ci    /* Check how the rewind fits into multiples of the matching period. */
9653a5a1b3Sopenharmony_ci    remainder = (in_rewind_frames + history_frames) % matching_period;
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci    /* If possible, use between 2 and 3 times the resampler delay */
9953a5a1b3Sopenharmony_ci    if (remainder < (size_t)delay && history_frames - remainder <= history_max)
10053a5a1b3Sopenharmony_ci        total_frames = in_rewind_frames + history_frames - remainder;
10153a5a1b3Sopenharmony_ci    /* Else, try above 3 times the delay */
10253a5a1b3Sopenharmony_ci    else if (history_frames + matching_period - remainder <= history_max)
10353a5a1b3Sopenharmony_ci        total_frames = in_rewind_frames + history_frames + matching_period - remainder;
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    if (total_frames != 0)
10653a5a1b3Sopenharmony_ci        /* We found a perfect match. */
10753a5a1b3Sopenharmony_ci        history_frames = total_frames - in_rewind_frames;
10853a5a1b3Sopenharmony_ci    else {
10953a5a1b3Sopenharmony_ci        /* Try to use 2.5 times the delay. */
11053a5a1b3Sopenharmony_ci        history_frames = PA_MIN((size_t)(delay * 2.5), history_max);
11153a5a1b3Sopenharmony_ci        pa_log_debug("No usable integral matching period");
11253a5a1b3Sopenharmony_ci    }
11353a5a1b3Sopenharmony_ci
11453a5a1b3Sopenharmony_ci    return history_frames * r->i_fz;
11553a5a1b3Sopenharmony_ci}
11653a5a1b3Sopenharmony_ci
11753a5a1b3Sopenharmony_cistatic struct volume_factor_entry *volume_factor_entry_new(const char *key, const pa_cvolume *volume) {
11853a5a1b3Sopenharmony_ci    struct volume_factor_entry *entry;
11953a5a1b3Sopenharmony_ci
12053a5a1b3Sopenharmony_ci    pa_assert(key);
12153a5a1b3Sopenharmony_ci    pa_assert(volume);
12253a5a1b3Sopenharmony_ci
12353a5a1b3Sopenharmony_ci    entry = pa_xnew(struct volume_factor_entry, 1);
12453a5a1b3Sopenharmony_ci    entry->key = pa_xstrdup(key);
12553a5a1b3Sopenharmony_ci
12653a5a1b3Sopenharmony_ci    entry->volume = *volume;
12753a5a1b3Sopenharmony_ci
12853a5a1b3Sopenharmony_ci    return entry;
12953a5a1b3Sopenharmony_ci}
13053a5a1b3Sopenharmony_ci
13153a5a1b3Sopenharmony_cistatic void volume_factor_entry_free(struct volume_factor_entry *volume_entry) {
13253a5a1b3Sopenharmony_ci    pa_assert(volume_entry);
13353a5a1b3Sopenharmony_ci
13453a5a1b3Sopenharmony_ci    pa_xfree(volume_entry->key);
13553a5a1b3Sopenharmony_ci    pa_xfree(volume_entry);
13653a5a1b3Sopenharmony_ci}
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_cistatic void volume_factor_from_hashmap(pa_cvolume *v, pa_hashmap *items, uint8_t channels) {
13953a5a1b3Sopenharmony_ci    struct volume_factor_entry *entry;
14053a5a1b3Sopenharmony_ci    void *state = NULL;
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_ci    pa_cvolume_reset(v, channels);
14353a5a1b3Sopenharmony_ci    PA_HASHMAP_FOREACH(entry, items, state)
14453a5a1b3Sopenharmony_ci        pa_sw_cvolume_multiply(v, v, &entry->volume);
14553a5a1b3Sopenharmony_ci}
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_cistatic void sink_input_free(pa_object *o);
14853a5a1b3Sopenharmony_cistatic void set_real_ratio(pa_sink_input *i, const pa_cvolume *v);
14953a5a1b3Sopenharmony_ci
15053a5a1b3Sopenharmony_cistatic int check_passthrough_connection(bool passthrough, pa_sink *dest) {
15153a5a1b3Sopenharmony_ci    if (pa_sink_is_passthrough(dest)) {
15253a5a1b3Sopenharmony_ci        pa_log_warn("Sink is already connected to PASSTHROUGH input");
15353a5a1b3Sopenharmony_ci        return -PA_ERR_BUSY;
15453a5a1b3Sopenharmony_ci    }
15553a5a1b3Sopenharmony_ci
15653a5a1b3Sopenharmony_ci    /* If current input(s) exist, check new input is not PASSTHROUGH */
15753a5a1b3Sopenharmony_ci    if (pa_idxset_size(dest->inputs) > 0 && passthrough) {
15853a5a1b3Sopenharmony_ci        pa_log_warn("Sink is already connected, cannot accept new PASSTHROUGH INPUT");
15953a5a1b3Sopenharmony_ci        return -PA_ERR_BUSY;
16053a5a1b3Sopenharmony_ci    }
16153a5a1b3Sopenharmony_ci
16253a5a1b3Sopenharmony_ci    return PA_OK;
16353a5a1b3Sopenharmony_ci}
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_cipa_sink_input_new_data* pa_sink_input_new_data_init(pa_sink_input_new_data *data) {
16653a5a1b3Sopenharmony_ci    pa_assert(data);
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci    pa_zero(*data);
16953a5a1b3Sopenharmony_ci    data->resample_method = PA_RESAMPLER_INVALID;
17053a5a1b3Sopenharmony_ci    data->proplist = pa_proplist_new();
17153a5a1b3Sopenharmony_ci    data->volume_writable = true;
17253a5a1b3Sopenharmony_ci
17353a5a1b3Sopenharmony_ci    data->volume_factor_items = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
17453a5a1b3Sopenharmony_ci                                                    (pa_free_cb_t) volume_factor_entry_free);
17553a5a1b3Sopenharmony_ci    data->volume_factor_sink_items = pa_hashmap_new_full(pa_idxset_string_hash_func, pa_idxset_string_compare_func, NULL,
17653a5a1b3Sopenharmony_ci                                                         (pa_free_cb_t) volume_factor_entry_free);
17753a5a1b3Sopenharmony_ci
17853a5a1b3Sopenharmony_ci    return data;
17953a5a1b3Sopenharmony_ci}
18053a5a1b3Sopenharmony_ci
18153a5a1b3Sopenharmony_civoid pa_sink_input_new_data_set_sample_spec(pa_sink_input_new_data *data, const pa_sample_spec *spec) {
18253a5a1b3Sopenharmony_ci    pa_assert(data);
18353a5a1b3Sopenharmony_ci
18453a5a1b3Sopenharmony_ci    if ((data->sample_spec_is_set = !!spec))
18553a5a1b3Sopenharmony_ci        data->sample_spec = *spec;
18653a5a1b3Sopenharmony_ci}
18753a5a1b3Sopenharmony_ci
18853a5a1b3Sopenharmony_civoid pa_sink_input_new_data_set_channel_map(pa_sink_input_new_data *data, const pa_channel_map *map) {
18953a5a1b3Sopenharmony_ci    pa_assert(data);
19053a5a1b3Sopenharmony_ci
19153a5a1b3Sopenharmony_ci    if ((data->channel_map_is_set = !!map))
19253a5a1b3Sopenharmony_ci        data->channel_map = *map;
19353a5a1b3Sopenharmony_ci}
19453a5a1b3Sopenharmony_ci
19553a5a1b3Sopenharmony_cibool pa_sink_input_new_data_is_passthrough(pa_sink_input_new_data *data) {
19653a5a1b3Sopenharmony_ci    pa_assert(data);
19753a5a1b3Sopenharmony_ci
19853a5a1b3Sopenharmony_ci    if (PA_LIKELY(data->format) && PA_UNLIKELY(!pa_format_info_is_pcm(data->format)))
19953a5a1b3Sopenharmony_ci        return true;
20053a5a1b3Sopenharmony_ci
20153a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(data->flags & PA_SINK_INPUT_PASSTHROUGH))
20253a5a1b3Sopenharmony_ci        return true;
20353a5a1b3Sopenharmony_ci
20453a5a1b3Sopenharmony_ci    return false;
20553a5a1b3Sopenharmony_ci}
20653a5a1b3Sopenharmony_ci
20753a5a1b3Sopenharmony_civoid pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cvolume *volume) {
20853a5a1b3Sopenharmony_ci    pa_assert(data);
20953a5a1b3Sopenharmony_ci    pa_assert(data->volume_writable);
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci    if ((data->volume_is_set = !!volume))
21253a5a1b3Sopenharmony_ci        data->volume = *volume;
21353a5a1b3Sopenharmony_ci}
21453a5a1b3Sopenharmony_ci
21553a5a1b3Sopenharmony_civoid pa_sink_input_new_data_add_volume_factor(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor) {
21653a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
21753a5a1b3Sopenharmony_ci
21853a5a1b3Sopenharmony_ci    pa_assert(data);
21953a5a1b3Sopenharmony_ci    pa_assert(key);
22053a5a1b3Sopenharmony_ci    pa_assert(volume_factor);
22153a5a1b3Sopenharmony_ci
22253a5a1b3Sopenharmony_ci    v = volume_factor_entry_new(key, volume_factor);
22353a5a1b3Sopenharmony_ci    pa_assert_se(pa_hashmap_put(data->volume_factor_items, v->key, v) >= 0);
22453a5a1b3Sopenharmony_ci}
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_civoid pa_sink_input_new_data_add_volume_factor_sink(pa_sink_input_new_data *data, const char *key, const pa_cvolume *volume_factor) {
22753a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
22853a5a1b3Sopenharmony_ci
22953a5a1b3Sopenharmony_ci    pa_assert(data);
23053a5a1b3Sopenharmony_ci    pa_assert(key);
23153a5a1b3Sopenharmony_ci    pa_assert(volume_factor);
23253a5a1b3Sopenharmony_ci
23353a5a1b3Sopenharmony_ci    v = volume_factor_entry_new(key, volume_factor);
23453a5a1b3Sopenharmony_ci    pa_assert_se(pa_hashmap_put(data->volume_factor_sink_items, v->key, v) >= 0);
23553a5a1b3Sopenharmony_ci}
23653a5a1b3Sopenharmony_ci
23753a5a1b3Sopenharmony_civoid pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, bool mute) {
23853a5a1b3Sopenharmony_ci    pa_assert(data);
23953a5a1b3Sopenharmony_ci
24053a5a1b3Sopenharmony_ci    data->muted_is_set = true;
24153a5a1b3Sopenharmony_ci    data->muted = mute;
24253a5a1b3Sopenharmony_ci}
24353a5a1b3Sopenharmony_ci
24453a5a1b3Sopenharmony_cibool pa_sink_input_new_data_set_sink(pa_sink_input_new_data *data, pa_sink *s, bool save, bool requested_by_application) {
24553a5a1b3Sopenharmony_ci    bool ret = true;
24653a5a1b3Sopenharmony_ci    pa_idxset *formats = NULL;
24753a5a1b3Sopenharmony_ci
24853a5a1b3Sopenharmony_ci    pa_assert(data);
24953a5a1b3Sopenharmony_ci    pa_assert(s);
25053a5a1b3Sopenharmony_ci
25153a5a1b3Sopenharmony_ci    if (!data->req_formats) {
25253a5a1b3Sopenharmony_ci        /* We're not working with the extended API */
25353a5a1b3Sopenharmony_ci        data->sink = s;
25453a5a1b3Sopenharmony_ci        if (save) {
25553a5a1b3Sopenharmony_ci            pa_xfree(data->preferred_sink);
25653a5a1b3Sopenharmony_ci            data->preferred_sink = pa_xstrdup(s->name);
25753a5a1b3Sopenharmony_ci	}
25853a5a1b3Sopenharmony_ci        data->sink_requested_by_application = requested_by_application;
25953a5a1b3Sopenharmony_ci    } else {
26053a5a1b3Sopenharmony_ci        /* Extended API: let's see if this sink supports the formats the client can provide */
26153a5a1b3Sopenharmony_ci        formats = pa_sink_check_formats(s, data->req_formats);
26253a5a1b3Sopenharmony_ci
26353a5a1b3Sopenharmony_ci        if (formats && !pa_idxset_isempty(formats)) {
26453a5a1b3Sopenharmony_ci            /* Sink supports at least one of the requested formats */
26553a5a1b3Sopenharmony_ci            data->sink = s;
26653a5a1b3Sopenharmony_ci	    if (save) {
26753a5a1b3Sopenharmony_ci		pa_xfree(data->preferred_sink);
26853a5a1b3Sopenharmony_ci		data->preferred_sink = pa_xstrdup(s->name);
26953a5a1b3Sopenharmony_ci	    }
27053a5a1b3Sopenharmony_ci            data->sink_requested_by_application = requested_by_application;
27153a5a1b3Sopenharmony_ci            if (data->nego_formats)
27253a5a1b3Sopenharmony_ci                pa_idxset_free(data->nego_formats, (pa_free_cb_t) pa_format_info_free);
27353a5a1b3Sopenharmony_ci            data->nego_formats = formats;
27453a5a1b3Sopenharmony_ci        } else {
27553a5a1b3Sopenharmony_ci            /* Sink doesn't support any of the formats requested by the client */
27653a5a1b3Sopenharmony_ci            if (formats)
27753a5a1b3Sopenharmony_ci                pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free);
27853a5a1b3Sopenharmony_ci            ret = false;
27953a5a1b3Sopenharmony_ci        }
28053a5a1b3Sopenharmony_ci    }
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci    return ret;
28353a5a1b3Sopenharmony_ci}
28453a5a1b3Sopenharmony_ci
28553a5a1b3Sopenharmony_cibool pa_sink_input_new_data_set_formats(pa_sink_input_new_data *data, pa_idxset *formats) {
28653a5a1b3Sopenharmony_ci    pa_assert(data);
28753a5a1b3Sopenharmony_ci    pa_assert(formats);
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci    if (data->req_formats)
29053a5a1b3Sopenharmony_ci        pa_idxset_free(data->req_formats, (pa_free_cb_t) pa_format_info_free);
29153a5a1b3Sopenharmony_ci
29253a5a1b3Sopenharmony_ci    data->req_formats = formats;
29353a5a1b3Sopenharmony_ci
29453a5a1b3Sopenharmony_ci    if (data->sink) {
29553a5a1b3Sopenharmony_ci        /* Trigger format negotiation */
29653a5a1b3Sopenharmony_ci        return pa_sink_input_new_data_set_sink(data, data->sink, (data->preferred_sink != NULL), data->sink_requested_by_application);
29753a5a1b3Sopenharmony_ci    }
29853a5a1b3Sopenharmony_ci
29953a5a1b3Sopenharmony_ci    return true;
30053a5a1b3Sopenharmony_ci}
30153a5a1b3Sopenharmony_ci
30253a5a1b3Sopenharmony_civoid pa_sink_input_new_data_done(pa_sink_input_new_data *data) {
30353a5a1b3Sopenharmony_ci    pa_assert(data);
30453a5a1b3Sopenharmony_ci
30553a5a1b3Sopenharmony_ci    if (data->req_formats)
30653a5a1b3Sopenharmony_ci        pa_idxset_free(data->req_formats, (pa_free_cb_t) pa_format_info_free);
30753a5a1b3Sopenharmony_ci
30853a5a1b3Sopenharmony_ci    if (data->nego_formats)
30953a5a1b3Sopenharmony_ci        pa_idxset_free(data->nego_formats, (pa_free_cb_t) pa_format_info_free);
31053a5a1b3Sopenharmony_ci
31153a5a1b3Sopenharmony_ci    if (data->format)
31253a5a1b3Sopenharmony_ci        pa_format_info_free(data->format);
31353a5a1b3Sopenharmony_ci
31453a5a1b3Sopenharmony_ci    if (data->volume_factor_items)
31553a5a1b3Sopenharmony_ci        pa_hashmap_free(data->volume_factor_items);
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci    if (data->volume_factor_sink_items)
31853a5a1b3Sopenharmony_ci        pa_hashmap_free(data->volume_factor_sink_items);
31953a5a1b3Sopenharmony_ci
32053a5a1b3Sopenharmony_ci    if (data->preferred_sink)
32153a5a1b3Sopenharmony_ci        pa_xfree(data->preferred_sink);
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci    pa_proplist_free(data->proplist);
32453a5a1b3Sopenharmony_ci}
32553a5a1b3Sopenharmony_ci
32653a5a1b3Sopenharmony_ci/* Called from main context */
32753a5a1b3Sopenharmony_cistatic void reset_callbacks(pa_sink_input *i) {
32853a5a1b3Sopenharmony_ci    pa_assert(i);
32953a5a1b3Sopenharmony_ci
33053a5a1b3Sopenharmony_ci    i->pop = NULL;
33153a5a1b3Sopenharmony_ci    i->process_underrun = NULL;
33253a5a1b3Sopenharmony_ci    i->process_rewind = NULL;
33353a5a1b3Sopenharmony_ci    i->update_max_rewind = NULL;
33453a5a1b3Sopenharmony_ci    i->update_max_request = NULL;
33553a5a1b3Sopenharmony_ci    i->update_sink_requested_latency = NULL;
33653a5a1b3Sopenharmony_ci    i->update_sink_latency_range = NULL;
33753a5a1b3Sopenharmony_ci    i->update_sink_fixed_latency = NULL;
33853a5a1b3Sopenharmony_ci    i->attach = NULL;
33953a5a1b3Sopenharmony_ci    i->detach = NULL;
34053a5a1b3Sopenharmony_ci    i->suspend = NULL;
34153a5a1b3Sopenharmony_ci    i->suspend_within_thread = NULL;
34253a5a1b3Sopenharmony_ci    i->moving = NULL;
34353a5a1b3Sopenharmony_ci    i->kill = NULL;
34453a5a1b3Sopenharmony_ci    i->get_latency = NULL;
34553a5a1b3Sopenharmony_ci    i->state_change = NULL;
34653a5a1b3Sopenharmony_ci    i->may_move_to = NULL;
34753a5a1b3Sopenharmony_ci    i->send_event = NULL;
34853a5a1b3Sopenharmony_ci    i->volume_changed = NULL;
34953a5a1b3Sopenharmony_ci    i->mute_changed = NULL;
35053a5a1b3Sopenharmony_ci    i->get_max_rewind_limit = NULL;
35153a5a1b3Sopenharmony_ci    i->process_underrun_ohos = NULL;
35253a5a1b3Sopenharmony_ci}
35353a5a1b3Sopenharmony_ci
35453a5a1b3Sopenharmony_ci/* Called from main context */
35553a5a1b3Sopenharmony_ciint pa_sink_input_new(
35653a5a1b3Sopenharmony_ci        pa_sink_input **_i,
35753a5a1b3Sopenharmony_ci        pa_core *core,
35853a5a1b3Sopenharmony_ci        pa_sink_input_new_data *data) {
35953a5a1b3Sopenharmony_ci
36053a5a1b3Sopenharmony_ci    pa_sink_input *i;
36153a5a1b3Sopenharmony_ci    pa_resampler *resampler = NULL;
36253a5a1b3Sopenharmony_ci    char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], fmt[PA_FORMAT_INFO_SNPRINT_MAX];
36353a5a1b3Sopenharmony_ci    pa_channel_map volume_map;
36453a5a1b3Sopenharmony_ci    int r;
36553a5a1b3Sopenharmony_ci    char *pt;
36653a5a1b3Sopenharmony_ci    char *memblockq_name;
36753a5a1b3Sopenharmony_ci    pa_memchunk silence;
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci    pa_assert(_i);
37053a5a1b3Sopenharmony_ci    pa_assert(core);
37153a5a1b3Sopenharmony_ci    pa_assert(data);
37253a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
37353a5a1b3Sopenharmony_ci
37453a5a1b3Sopenharmony_ci    if (data->client)
37553a5a1b3Sopenharmony_ci        pa_proplist_update(data->proplist, PA_UPDATE_MERGE, data->client->proplist);
37653a5a1b3Sopenharmony_ci
37753a5a1b3Sopenharmony_ci    if (data->origin_sink && (data->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER))
37853a5a1b3Sopenharmony_ci        data->volume_writable = false;
37953a5a1b3Sopenharmony_ci
38053a5a1b3Sopenharmony_ci    if (!data->req_formats) {
38153a5a1b3Sopenharmony_ci        /* From this point on, we want to work only with formats, and get back
38253a5a1b3Sopenharmony_ci         * to using the sample spec and channel map after all decisions w.r.t.
38353a5a1b3Sopenharmony_ci         * routing are complete. */
38453a5a1b3Sopenharmony_ci        pa_format_info *f;
38553a5a1b3Sopenharmony_ci        pa_idxset *formats;
38653a5a1b3Sopenharmony_ci
38753a5a1b3Sopenharmony_ci        f = pa_format_info_from_sample_spec2(&data->sample_spec, data->channel_map_is_set ? &data->channel_map : NULL,
38853a5a1b3Sopenharmony_ci                                             !(data->flags & PA_SINK_INPUT_FIX_FORMAT),
38953a5a1b3Sopenharmony_ci                                             !(data->flags & PA_SINK_INPUT_FIX_RATE),
39053a5a1b3Sopenharmony_ci                                             !(data->flags & PA_SINK_INPUT_FIX_CHANNELS));
39153a5a1b3Sopenharmony_ci        if (!f)
39253a5a1b3Sopenharmony_ci            return -PA_ERR_INVALID;
39353a5a1b3Sopenharmony_ci
39453a5a1b3Sopenharmony_ci        formats = pa_idxset_new(NULL, NULL);
39553a5a1b3Sopenharmony_ci        pa_idxset_put(formats, f, NULL);
39653a5a1b3Sopenharmony_ci        pa_sink_input_new_data_set_formats(data, formats);
39753a5a1b3Sopenharmony_ci    }
39853a5a1b3Sopenharmony_ci
39953a5a1b3Sopenharmony_ci    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], data)) < 0)
40053a5a1b3Sopenharmony_ci        return r;
40153a5a1b3Sopenharmony_ci
40253a5a1b3Sopenharmony_ci    pa_return_val_if_fail(!data->driver || pa_utf8_valid(data->driver), -PA_ERR_INVALID);
40353a5a1b3Sopenharmony_ci
40453a5a1b3Sopenharmony_ci    if (!data->sink) {
40553a5a1b3Sopenharmony_ci        pa_sink *sink = pa_namereg_get(core, NULL, PA_NAMEREG_SINK);
40653a5a1b3Sopenharmony_ci        pa_return_val_if_fail(sink, -PA_ERR_NOENTITY);
40753a5a1b3Sopenharmony_ci        pa_sink_input_new_data_set_sink(data, sink, false, false);
40853a5a1b3Sopenharmony_ci    }
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    /* If something didn't pick a format for us, pick the top-most format since
41153a5a1b3Sopenharmony_ci     * we assume this is sorted in priority order */
41253a5a1b3Sopenharmony_ci    if (!data->format && data->nego_formats && !pa_idxset_isempty(data->nego_formats))
41353a5a1b3Sopenharmony_ci        data->format = pa_format_info_copy(pa_idxset_first(data->nego_formats, NULL));
41453a5a1b3Sopenharmony_ci
41553a5a1b3Sopenharmony_ci    if (PA_LIKELY(data->format)) {
41653a5a1b3Sopenharmony_ci        /* We know that data->sink is set, because data->format has been set.
41753a5a1b3Sopenharmony_ci         * data->format is set after a successful format negotiation, and that
41853a5a1b3Sopenharmony_ci         * can't happen before data->sink has been set. */
41953a5a1b3Sopenharmony_ci        pa_assert(data->sink);
42053a5a1b3Sopenharmony_ci
42153a5a1b3Sopenharmony_ci        pa_log_debug("Negotiated format: %s", pa_format_info_snprint(fmt, sizeof(fmt), data->format));
42253a5a1b3Sopenharmony_ci    } else {
42353a5a1b3Sopenharmony_ci        pa_format_info *format;
42453a5a1b3Sopenharmony_ci        uint32_t idx;
42553a5a1b3Sopenharmony_ci
42653a5a1b3Sopenharmony_ci        pa_log_info("Sink does not support any requested format:");
42753a5a1b3Sopenharmony_ci        PA_IDXSET_FOREACH(format, data->req_formats, idx)
42853a5a1b3Sopenharmony_ci            pa_log_info(" -- %s", pa_format_info_snprint(fmt, sizeof(fmt), format));
42953a5a1b3Sopenharmony_ci
43053a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
43153a5a1b3Sopenharmony_ci    }
43253a5a1b3Sopenharmony_ci
43353a5a1b3Sopenharmony_ci    pa_return_val_if_fail(PA_SINK_IS_LINKED(data->sink->state), -PA_ERR_BADSTATE);
43453a5a1b3Sopenharmony_ci    pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink
43553a5a1b3Sopenharmony_ci                                               && data->sync_base->state == PA_SINK_INPUT_CORKED),
43653a5a1b3Sopenharmony_ci                          -PA_ERR_INVALID);
43753a5a1b3Sopenharmony_ci
43853a5a1b3Sopenharmony_ci    /* Routing is done. We have a sink and a format. */
43953a5a1b3Sopenharmony_ci
44053a5a1b3Sopenharmony_ci    if (data->volume_is_set && !pa_sink_input_new_data_is_passthrough(data)) {
44153a5a1b3Sopenharmony_ci        /* If volume is set, we need to save the original data->channel_map,
44253a5a1b3Sopenharmony_ci         * so that we can remap the volume from the original channel map to the
44353a5a1b3Sopenharmony_ci         * final channel map of the stream in case data->channel_map gets
44453a5a1b3Sopenharmony_ci         * modified in pa_format_info_to_sample_spec2(). */
44553a5a1b3Sopenharmony_ci        r = pa_stream_get_volume_channel_map(&data->volume, data->channel_map_is_set ? &data->channel_map : NULL, data->format, &volume_map);
44653a5a1b3Sopenharmony_ci        if (r < 0)
44753a5a1b3Sopenharmony_ci            return r;
44853a5a1b3Sopenharmony_ci    } else {
44953a5a1b3Sopenharmony_ci        /* Initialize volume_map to invalid state. We check the state later to
45053a5a1b3Sopenharmony_ci         * determine if volume remapping is needed. */
45153a5a1b3Sopenharmony_ci        pa_channel_map_init(&volume_map);
45253a5a1b3Sopenharmony_ci    }
45353a5a1b3Sopenharmony_ci
45453a5a1b3Sopenharmony_ci    /* Now populate the sample spec and channel map according to the final
45553a5a1b3Sopenharmony_ci     * format that we've negotiated */
45653a5a1b3Sopenharmony_ci    r = pa_format_info_to_sample_spec2(data->format, &data->sample_spec, &data->channel_map, &data->sink->sample_spec,
45753a5a1b3Sopenharmony_ci                                       &data->sink->channel_map);
45853a5a1b3Sopenharmony_ci    if (r < 0)
45953a5a1b3Sopenharmony_ci        return r;
46053a5a1b3Sopenharmony_ci
46153a5a1b3Sopenharmony_ci    r = check_passthrough_connection(pa_sink_input_new_data_is_passthrough(data), data->sink);
46253a5a1b3Sopenharmony_ci    if (r != PA_OK)
46353a5a1b3Sopenharmony_ci        return r;
46453a5a1b3Sopenharmony_ci
46553a5a1b3Sopenharmony_ci    /* Don't restore (or save) stream volume for passthrough streams and
46653a5a1b3Sopenharmony_ci     * prevent attenuation/gain */
46753a5a1b3Sopenharmony_ci    if (pa_sink_input_new_data_is_passthrough(data)) {
46853a5a1b3Sopenharmony_ci        data->volume_is_set = true;
46953a5a1b3Sopenharmony_ci        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
47053a5a1b3Sopenharmony_ci        data->volume_is_absolute = true;
47153a5a1b3Sopenharmony_ci        data->save_volume = false;
47253a5a1b3Sopenharmony_ci    }
47353a5a1b3Sopenharmony_ci
47453a5a1b3Sopenharmony_ci    if (!data->volume_is_set) {
47553a5a1b3Sopenharmony_ci        pa_cvolume_reset(&data->volume, data->sample_spec.channels);
47653a5a1b3Sopenharmony_ci        data->volume_is_absolute = false;
47753a5a1b3Sopenharmony_ci        data->save_volume = false;
47853a5a1b3Sopenharmony_ci    }
47953a5a1b3Sopenharmony_ci
48053a5a1b3Sopenharmony_ci    if (!data->volume_writable)
48153a5a1b3Sopenharmony_ci        data->save_volume = false;
48253a5a1b3Sopenharmony_ci
48353a5a1b3Sopenharmony_ci    if (pa_channel_map_valid(&volume_map))
48453a5a1b3Sopenharmony_ci        /* The original volume channel map may be different than the final
48553a5a1b3Sopenharmony_ci         * stream channel map, so remapping may be needed. */
48653a5a1b3Sopenharmony_ci        pa_cvolume_remap(&data->volume, &volume_map, &data->channel_map);
48753a5a1b3Sopenharmony_ci
48853a5a1b3Sopenharmony_ci    if (!data->muted_is_set)
48953a5a1b3Sopenharmony_ci        data->muted = false;
49053a5a1b3Sopenharmony_ci
49153a5a1b3Sopenharmony_ci    if (!(data->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
49253a5a1b3Sopenharmony_ci        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
49353a5a1b3Sopenharmony_ci        /* try to change sink format and rate. This is done before the FIXATE hook since
49453a5a1b3Sopenharmony_ci           module-suspend-on-idle can resume a sink */
49553a5a1b3Sopenharmony_ci
49653a5a1b3Sopenharmony_ci        pa_log_info("Trying to change sample spec");
49753a5a1b3Sopenharmony_ci        pa_sink_reconfigure(data->sink, &data->sample_spec, pa_sink_input_new_data_is_passthrough(data));
49853a5a1b3Sopenharmony_ci    }
49953a5a1b3Sopenharmony_ci
50053a5a1b3Sopenharmony_ci    if (pa_sink_input_new_data_is_passthrough(data) &&
50153a5a1b3Sopenharmony_ci        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec)) {
50253a5a1b3Sopenharmony_ci        /* rate update failed, or other parts of sample spec didn't match */
50353a5a1b3Sopenharmony_ci
50453a5a1b3Sopenharmony_ci        pa_log_debug("Could not update sink sample spec to match passthrough stream");
50553a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
50653a5a1b3Sopenharmony_ci    }
50753a5a1b3Sopenharmony_ci
50853a5a1b3Sopenharmony_ci    if (data->resample_method == PA_RESAMPLER_INVALID)
50953a5a1b3Sopenharmony_ci        data->resample_method = core->resample_method;
51053a5a1b3Sopenharmony_ci
51153a5a1b3Sopenharmony_ci    pa_return_val_if_fail(data->resample_method < PA_RESAMPLER_MAX, -PA_ERR_INVALID);
51253a5a1b3Sopenharmony_ci
51353a5a1b3Sopenharmony_ci    if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
51453a5a1b3Sopenharmony_ci        return r;
51553a5a1b3Sopenharmony_ci
51653a5a1b3Sopenharmony_ci    if ((data->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND) &&
51753a5a1b3Sopenharmony_ci        data->sink->state == PA_SINK_SUSPENDED) {
51853a5a1b3Sopenharmony_ci        pa_log_warn("Failed to create sink input: sink is suspended.");
51953a5a1b3Sopenharmony_ci        return -PA_ERR_BADSTATE;
52053a5a1b3Sopenharmony_ci    }
52153a5a1b3Sopenharmony_ci
52253a5a1b3Sopenharmony_ci    if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
52353a5a1b3Sopenharmony_ci        pa_log_warn("Failed to create sink input: too many inputs per sink.");
52453a5a1b3Sopenharmony_ci        return -PA_ERR_TOOLARGE;
52553a5a1b3Sopenharmony_ci    }
52653a5a1b3Sopenharmony_ci
52753a5a1b3Sopenharmony_ci    if ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
52853a5a1b3Sopenharmony_ci        !pa_sample_spec_equal(&data->sample_spec, &data->sink->sample_spec) ||
52953a5a1b3Sopenharmony_ci        !pa_channel_map_equal(&data->channel_map, &data->sink->channel_map)) {
53053a5a1b3Sopenharmony_ci
53153a5a1b3Sopenharmony_ci        /* Note: for passthrough content we need to adjust the output rate to that of the current sink-input */
53253a5a1b3Sopenharmony_ci        if (!pa_sink_input_new_data_is_passthrough(data)) /* no resampler for passthrough content */
53353a5a1b3Sopenharmony_ci            if (!(resampler = pa_resampler_new(
53453a5a1b3Sopenharmony_ci                          core->mempool,
53553a5a1b3Sopenharmony_ci                          &data->sample_spec, &data->channel_map,
53653a5a1b3Sopenharmony_ci                          &data->sink->sample_spec, &data->sink->channel_map,
53753a5a1b3Sopenharmony_ci                          core->lfe_crossover_freq,
53853a5a1b3Sopenharmony_ci                          data->resample_method,
53953a5a1b3Sopenharmony_ci                          ((data->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
54053a5a1b3Sopenharmony_ci                          ((data->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
54153a5a1b3Sopenharmony_ci                          (core->disable_remixing || (data->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
54253a5a1b3Sopenharmony_ci                          (core->remixing_use_all_sink_channels ? 0 : PA_RESAMPLER_NO_FILL_SINK) |
54353a5a1b3Sopenharmony_ci                          (core->remixing_produce_lfe ? PA_RESAMPLER_PRODUCE_LFE : 0) |
54453a5a1b3Sopenharmony_ci                          (core->remixing_consume_lfe ? PA_RESAMPLER_CONSUME_LFE : 0)))) {
54553a5a1b3Sopenharmony_ci                pa_log_warn("Unsupported resampling operation.");
54653a5a1b3Sopenharmony_ci                return -PA_ERR_NOTSUPPORTED;
54753a5a1b3Sopenharmony_ci            }
54853a5a1b3Sopenharmony_ci    }
54953a5a1b3Sopenharmony_ci
55053a5a1b3Sopenharmony_ci    i = pa_msgobject_new(pa_sink_input);
55153a5a1b3Sopenharmony_ci    i->parent.parent.free = sink_input_free;
55253a5a1b3Sopenharmony_ci    i->parent.process_msg = pa_sink_input_process_msg;
55353a5a1b3Sopenharmony_ci
55453a5a1b3Sopenharmony_ci    i->core = core;
55553a5a1b3Sopenharmony_ci    i->state = PA_SINK_INPUT_INIT;
55653a5a1b3Sopenharmony_ci    i->flags = data->flags;
55753a5a1b3Sopenharmony_ci    i->proplist = pa_proplist_copy(data->proplist);
55853a5a1b3Sopenharmony_ci    i->driver = pa_xstrdup(pa_path_get_filename(data->driver));
55953a5a1b3Sopenharmony_ci    i->module = data->module;
56053a5a1b3Sopenharmony_ci    i->sink = data->sink;
56153a5a1b3Sopenharmony_ci    i->sink_requested_by_application = data->sink_requested_by_application;
56253a5a1b3Sopenharmony_ci    i->origin_sink = data->origin_sink;
56353a5a1b3Sopenharmony_ci    i->client = data->client;
56453a5a1b3Sopenharmony_ci
56553a5a1b3Sopenharmony_ci    i->requested_resample_method = data->resample_method;
56653a5a1b3Sopenharmony_ci    i->actual_resample_method = resampler ? pa_resampler_get_method(resampler) : PA_RESAMPLER_INVALID;
56753a5a1b3Sopenharmony_ci    i->sample_spec = data->sample_spec;
56853a5a1b3Sopenharmony_ci    i->channel_map = data->channel_map;
56953a5a1b3Sopenharmony_ci    i->format = pa_format_info_copy(data->format);
57053a5a1b3Sopenharmony_ci
57153a5a1b3Sopenharmony_ci    if (!data->volume_is_absolute && pa_sink_flat_volume_enabled(i->sink)) {
57253a5a1b3Sopenharmony_ci        pa_cvolume remapped;
57353a5a1b3Sopenharmony_ci
57453a5a1b3Sopenharmony_ci        /* When the 'absolute' bool is not set then we'll treat the volume
57553a5a1b3Sopenharmony_ci         * as relative to the sink volume even in flat volume mode */
57653a5a1b3Sopenharmony_ci        remapped = data->sink->reference_volume;
57753a5a1b3Sopenharmony_ci        pa_cvolume_remap(&remapped, &data->sink->channel_map, &data->channel_map);
57853a5a1b3Sopenharmony_ci        pa_sw_cvolume_multiply(&i->volume, &data->volume, &remapped);
57953a5a1b3Sopenharmony_ci    } else
58053a5a1b3Sopenharmony_ci        i->volume = data->volume;
58153a5a1b3Sopenharmony_ci
58253a5a1b3Sopenharmony_ci    i->volume_factor_items = data->volume_factor_items;
58353a5a1b3Sopenharmony_ci    data->volume_factor_items = NULL;
58453a5a1b3Sopenharmony_ci    volume_factor_from_hashmap(&i->volume_factor, i->volume_factor_items, i->sample_spec.channels);
58553a5a1b3Sopenharmony_ci
58653a5a1b3Sopenharmony_ci    i->volume_factor_sink_items = data->volume_factor_sink_items;
58753a5a1b3Sopenharmony_ci    data->volume_factor_sink_items = NULL;
58853a5a1b3Sopenharmony_ci    volume_factor_from_hashmap(&i->volume_factor_sink, i->volume_factor_sink_items, i->sink->sample_spec.channels);
58953a5a1b3Sopenharmony_ci
59053a5a1b3Sopenharmony_ci    i->real_ratio = i->reference_ratio = data->volume;
59153a5a1b3Sopenharmony_ci    pa_cvolume_reset(&i->soft_volume, i->sample_spec.channels);
59253a5a1b3Sopenharmony_ci    pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels);
59353a5a1b3Sopenharmony_ci    i->volume_writable = data->volume_writable;
59453a5a1b3Sopenharmony_ci    i->save_volume = data->save_volume;
59553a5a1b3Sopenharmony_ci    i->preferred_sink = pa_xstrdup(data->preferred_sink);
59653a5a1b3Sopenharmony_ci    i->save_muted = data->save_muted;
59753a5a1b3Sopenharmony_ci
59853a5a1b3Sopenharmony_ci    i->muted = data->muted;
59953a5a1b3Sopenharmony_ci
60053a5a1b3Sopenharmony_ci    if (data->sync_base) {
60153a5a1b3Sopenharmony_ci        i->sync_next = data->sync_base->sync_next;
60253a5a1b3Sopenharmony_ci        i->sync_prev = data->sync_base;
60353a5a1b3Sopenharmony_ci
60453a5a1b3Sopenharmony_ci        if (data->sync_base->sync_next)
60553a5a1b3Sopenharmony_ci            data->sync_base->sync_next->sync_prev = i;
60653a5a1b3Sopenharmony_ci        data->sync_base->sync_next = i;
60753a5a1b3Sopenharmony_ci    } else
60853a5a1b3Sopenharmony_ci        i->sync_next = i->sync_prev = NULL;
60953a5a1b3Sopenharmony_ci
61053a5a1b3Sopenharmony_ci    i->direct_outputs = pa_idxset_new(NULL, NULL);
61153a5a1b3Sopenharmony_ci
61253a5a1b3Sopenharmony_ci    reset_callbacks(i);
61353a5a1b3Sopenharmony_ci    i->userdata = NULL;
61453a5a1b3Sopenharmony_ci
61553a5a1b3Sopenharmony_ci    i->thread_info.state = i->state;
61653a5a1b3Sopenharmony_ci    i->thread_info.attached = false;
61753a5a1b3Sopenharmony_ci    i->thread_info.sample_spec = i->sample_spec;
61853a5a1b3Sopenharmony_ci    i->thread_info.resampler = resampler;
61953a5a1b3Sopenharmony_ci    i->thread_info.soft_volume = i->soft_volume;
62053a5a1b3Sopenharmony_ci    i->thread_info.muted = i->muted;
62153a5a1b3Sopenharmony_ci    i->thread_info.requested_sink_latency = (pa_usec_t) -1;
62253a5a1b3Sopenharmony_ci    i->thread_info.rewrite_nbytes = 0;
62353a5a1b3Sopenharmony_ci    i->thread_info.rewrite_flush = false;
62453a5a1b3Sopenharmony_ci    i->thread_info.dont_rewind_render = false;
62553a5a1b3Sopenharmony_ci    i->thread_info.underrun_for = (uint64_t) -1;
62653a5a1b3Sopenharmony_ci    i->thread_info.underrun_for_sink = 0;
62753a5a1b3Sopenharmony_ci    i->thread_info.playing_for = 0;
62853a5a1b3Sopenharmony_ci    i->thread_info.direct_outputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
62953a5a1b3Sopenharmony_ci    i->thread_info.move_start_time = 0;
63053a5a1b3Sopenharmony_ci    i->thread_info.resampler_delay_frames = 0;
63153a5a1b3Sopenharmony_ci    i->thread_info.origin_sink_latency = 0;
63253a5a1b3Sopenharmony_ci    i->thread_info.dont_rewrite = false;
63353a5a1b3Sopenharmony_ci    i->origin_rewind_bytes = 0;
63453a5a1b3Sopenharmony_ci
63553a5a1b3Sopenharmony_ci    pa_atomic_store(&i->isFirstReaded, 0);
63653a5a1b3Sopenharmony_ci
63753a5a1b3Sopenharmony_ci    pa_assert_se(pa_idxset_put(core->sink_inputs, i, &i->index) == 0);
63853a5a1b3Sopenharmony_ci    pa_assert_se(pa_idxset_put(i->sink->inputs, pa_sink_input_ref(i), NULL) == 0);
63953a5a1b3Sopenharmony_ci
64053a5a1b3Sopenharmony_ci    if (i->client)
64153a5a1b3Sopenharmony_ci        pa_assert_se(pa_idxset_put(i->client->sink_inputs, i, NULL) >= 0);
64253a5a1b3Sopenharmony_ci
64353a5a1b3Sopenharmony_ci    memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
64453a5a1b3Sopenharmony_ci    i->thread_info.render_memblockq = pa_memblockq_new(
64553a5a1b3Sopenharmony_ci            memblockq_name,
64653a5a1b3Sopenharmony_ci            0,
64753a5a1b3Sopenharmony_ci            MEMBLOCKQ_MAXLENGTH,
64853a5a1b3Sopenharmony_ci            0,
64953a5a1b3Sopenharmony_ci            &i->sink->sample_spec,
65053a5a1b3Sopenharmony_ci            0,
65153a5a1b3Sopenharmony_ci            1,
65253a5a1b3Sopenharmony_ci            0,
65353a5a1b3Sopenharmony_ci            &i->sink->silence);
65453a5a1b3Sopenharmony_ci    pa_xfree(memblockq_name);
65553a5a1b3Sopenharmony_ci
65653a5a1b3Sopenharmony_ci    memblockq_name = pa_sprintf_malloc("sink input history memblockq [%u]", i->index);
65753a5a1b3Sopenharmony_ci    pa_sink_input_get_silence(i, &silence);
65853a5a1b3Sopenharmony_ci    i->thread_info.history_memblockq = pa_memblockq_new(
65953a5a1b3Sopenharmony_ci            memblockq_name,
66053a5a1b3Sopenharmony_ci            0,
66153a5a1b3Sopenharmony_ci            MEMBLOCKQ_MAXLENGTH,
66253a5a1b3Sopenharmony_ci            0,
66353a5a1b3Sopenharmony_ci            &i->sample_spec,
66453a5a1b3Sopenharmony_ci            0,
66553a5a1b3Sopenharmony_ci            1,
66653a5a1b3Sopenharmony_ci            0,
66753a5a1b3Sopenharmony_ci            &silence);
66853a5a1b3Sopenharmony_ci    pa_xfree(memblockq_name);
66953a5a1b3Sopenharmony_ci    pa_memblock_unref(silence.memblock);
67053a5a1b3Sopenharmony_ci
67153a5a1b3Sopenharmony_ci    pt = pa_proplist_to_string_sep(i->proplist, "\n    ");
67253a5a1b3Sopenharmony_ci    pa_log_info("Created input %u \"%s\" on %s with sample spec %s and channel map %s\n    %s",
67353a5a1b3Sopenharmony_ci                i->index,
67453a5a1b3Sopenharmony_ci                pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)),
67553a5a1b3Sopenharmony_ci                i->sink->name,
67653a5a1b3Sopenharmony_ci                pa_sample_spec_snprint(st, sizeof(st), &i->sample_spec),
67753a5a1b3Sopenharmony_ci                pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
67853a5a1b3Sopenharmony_ci                pt);
67953a5a1b3Sopenharmony_ci    pa_xfree(pt);
68053a5a1b3Sopenharmony_ci
68153a5a1b3Sopenharmony_ci    /* Don't forget to call pa_sink_input_put! */
68253a5a1b3Sopenharmony_ci
68353a5a1b3Sopenharmony_ci    *_i = i;
68453a5a1b3Sopenharmony_ci    return 0;
68553a5a1b3Sopenharmony_ci}
68653a5a1b3Sopenharmony_ci
68753a5a1b3Sopenharmony_ci/* Called from main context */
68853a5a1b3Sopenharmony_cistatic void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) {
68953a5a1b3Sopenharmony_ci    pa_assert(i);
69053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
69153a5a1b3Sopenharmony_ci
69253a5a1b3Sopenharmony_ci    if (!i->sink)
69353a5a1b3Sopenharmony_ci        return;
69453a5a1b3Sopenharmony_ci
69553a5a1b3Sopenharmony_ci    if (i->state == PA_SINK_INPUT_CORKED && state != PA_SINK_INPUT_CORKED)
69653a5a1b3Sopenharmony_ci        pa_assert_se(i->sink->n_corked -- >= 1);
69753a5a1b3Sopenharmony_ci    else if (i->state != PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_CORKED)
69853a5a1b3Sopenharmony_ci        i->sink->n_corked++;
69953a5a1b3Sopenharmony_ci}
70053a5a1b3Sopenharmony_ci
70153a5a1b3Sopenharmony_ci/* Called from main context */
70253a5a1b3Sopenharmony_cistatic void sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) {
70353a5a1b3Sopenharmony_ci    pa_sink_input *ssync;
70453a5a1b3Sopenharmony_ci    pa_assert(i);
70553a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
70653a5a1b3Sopenharmony_ci
70753a5a1b3Sopenharmony_ci    if (i->state == state)
70853a5a1b3Sopenharmony_ci        return;
70953a5a1b3Sopenharmony_ci
71053a5a1b3Sopenharmony_ci    if (i->sink) {
71153a5a1b3Sopenharmony_ci        if (i->state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING && pa_sink_used_by(i->sink) == 0 &&
71253a5a1b3Sopenharmony_ci            !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec)) {
71353a5a1b3Sopenharmony_ci            /* We were uncorked and the sink was not playing anything -- let's try
71453a5a1b3Sopenharmony_ci             * to update the sample format and rate to avoid resampling */
71553a5a1b3Sopenharmony_ci            pa_sink_reconfigure(i->sink, &i->sample_spec, pa_sink_input_is_passthrough(i));
71653a5a1b3Sopenharmony_ci        }
71753a5a1b3Sopenharmony_ci
71853a5a1b3Sopenharmony_ci        pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_STATE, PA_UINT_TO_PTR(state), 0, NULL) == 0);
71953a5a1b3Sopenharmony_ci    } else {
72053a5a1b3Sopenharmony_ci        /* If the sink is not valid, pa_sink_input_set_state_within_thread() must be called directly */
72153a5a1b3Sopenharmony_ci
72253a5a1b3Sopenharmony_ci        pa_sink_input_set_state_within_thread(i, state);
72353a5a1b3Sopenharmony_ci
72453a5a1b3Sopenharmony_ci        for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev)
72553a5a1b3Sopenharmony_ci            pa_sink_input_set_state_within_thread(ssync, state);
72653a5a1b3Sopenharmony_ci
72753a5a1b3Sopenharmony_ci        for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next)
72853a5a1b3Sopenharmony_ci            pa_sink_input_set_state_within_thread(ssync, state);
72953a5a1b3Sopenharmony_ci    }
73053a5a1b3Sopenharmony_ci
73153a5a1b3Sopenharmony_ci    update_n_corked(i, state);
73253a5a1b3Sopenharmony_ci    i->state = state;
73353a5a1b3Sopenharmony_ci
73453a5a1b3Sopenharmony_ci    for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev) {
73553a5a1b3Sopenharmony_ci        update_n_corked(ssync, state);
73653a5a1b3Sopenharmony_ci        ssync->state = state;
73753a5a1b3Sopenharmony_ci    }
73853a5a1b3Sopenharmony_ci    for (ssync = i->sync_next; ssync; ssync = ssync->sync_next) {
73953a5a1b3Sopenharmony_ci        update_n_corked(ssync, state);
74053a5a1b3Sopenharmony_ci        ssync->state = state;
74153a5a1b3Sopenharmony_ci    }
74253a5a1b3Sopenharmony_ci
74353a5a1b3Sopenharmony_ci    if (state != PA_SINK_INPUT_UNLINKED) {
74453a5a1b3Sopenharmony_ci        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], i);
74553a5a1b3Sopenharmony_ci
74653a5a1b3Sopenharmony_ci        for (ssync = i->sync_prev; ssync; ssync = ssync->sync_prev)
74753a5a1b3Sopenharmony_ci            pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
74853a5a1b3Sopenharmony_ci
74953a5a1b3Sopenharmony_ci        for (ssync = i->sync_next; ssync; ssync = ssync->sync_next)
75053a5a1b3Sopenharmony_ci            pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync);
75153a5a1b3Sopenharmony_ci
75253a5a1b3Sopenharmony_ci        if (PA_SINK_INPUT_IS_LINKED(state))
75353a5a1b3Sopenharmony_ci            pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
75453a5a1b3Sopenharmony_ci    }
75553a5a1b3Sopenharmony_ci
75653a5a1b3Sopenharmony_ci    if (i->sink)
75753a5a1b3Sopenharmony_ci        pa_sink_update_status(i->sink);
75853a5a1b3Sopenharmony_ci}
75953a5a1b3Sopenharmony_ci
76053a5a1b3Sopenharmony_ci/* Called from main context */
76153a5a1b3Sopenharmony_civoid pa_sink_input_unlink(pa_sink_input *i) {
76253a5a1b3Sopenharmony_ci    bool linked;
76353a5a1b3Sopenharmony_ci    pa_source_output *o, PA_UNUSED *p = NULL;
76453a5a1b3Sopenharmony_ci
76553a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
76653a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
76753a5a1b3Sopenharmony_ci
76853a5a1b3Sopenharmony_ci    /* See pa_sink_unlink() for a couple of comments how this function
76953a5a1b3Sopenharmony_ci     * works */
77053a5a1b3Sopenharmony_ci
77153a5a1b3Sopenharmony_ci    pa_sink_input_ref(i);
77253a5a1b3Sopenharmony_ci
77353a5a1b3Sopenharmony_ci    linked = PA_SINK_INPUT_IS_LINKED(i->state);
77453a5a1b3Sopenharmony_ci
77553a5a1b3Sopenharmony_ci    if (linked)
77653a5a1b3Sopenharmony_ci        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], i);
77753a5a1b3Sopenharmony_ci
77853a5a1b3Sopenharmony_ci    if (i->sync_prev)
77953a5a1b3Sopenharmony_ci        i->sync_prev->sync_next = i->sync_next;
78053a5a1b3Sopenharmony_ci    if (i->sync_next)
78153a5a1b3Sopenharmony_ci        i->sync_next->sync_prev = i->sync_prev;
78253a5a1b3Sopenharmony_ci
78353a5a1b3Sopenharmony_ci    i->sync_prev = i->sync_next = NULL;
78453a5a1b3Sopenharmony_ci
78553a5a1b3Sopenharmony_ci    pa_idxset_remove_by_data(i->core->sink_inputs, i, NULL);
78653a5a1b3Sopenharmony_ci
78753a5a1b3Sopenharmony_ci    if (i->sink)
78853a5a1b3Sopenharmony_ci        if (pa_idxset_remove_by_data(i->sink->inputs, i, NULL))
78953a5a1b3Sopenharmony_ci            pa_sink_input_unref(i);
79053a5a1b3Sopenharmony_ci
79153a5a1b3Sopenharmony_ci    if (i->client)
79253a5a1b3Sopenharmony_ci        pa_idxset_remove_by_data(i->client->sink_inputs, i, NULL);
79353a5a1b3Sopenharmony_ci
79453a5a1b3Sopenharmony_ci    while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
79553a5a1b3Sopenharmony_ci        pa_assert(o != p);
79653a5a1b3Sopenharmony_ci        pa_source_output_kill(o);
79753a5a1b3Sopenharmony_ci        p = o;
79853a5a1b3Sopenharmony_ci    }
79953a5a1b3Sopenharmony_ci
80053a5a1b3Sopenharmony_ci    update_n_corked(i, PA_SINK_INPUT_UNLINKED);
80153a5a1b3Sopenharmony_ci    i->state = PA_SINK_INPUT_UNLINKED;
80253a5a1b3Sopenharmony_ci
80353a5a1b3Sopenharmony_ci    if (linked && i->sink) {
80453a5a1b3Sopenharmony_ci        if (pa_sink_input_is_passthrough(i))
80553a5a1b3Sopenharmony_ci            pa_sink_leave_passthrough(i->sink);
80653a5a1b3Sopenharmony_ci
80753a5a1b3Sopenharmony_ci        /* We might need to update the sink's volume if we are in flat volume mode. */
80853a5a1b3Sopenharmony_ci        if (pa_sink_flat_volume_enabled(i->sink))
80953a5a1b3Sopenharmony_ci            pa_sink_set_volume(i->sink, NULL, false, false);
81053a5a1b3Sopenharmony_ci
81153a5a1b3Sopenharmony_ci        if (i->sink->asyncmsgq)
81253a5a1b3Sopenharmony_ci            pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_REMOVE_INPUT, i, 0, NULL) == 0);
81353a5a1b3Sopenharmony_ci    }
81453a5a1b3Sopenharmony_ci
81553a5a1b3Sopenharmony_ci    reset_callbacks(i);
81653a5a1b3Sopenharmony_ci
81753a5a1b3Sopenharmony_ci    if (i->sink) {
81853a5a1b3Sopenharmony_ci        if (PA_SINK_IS_LINKED(i->sink->state))
81953a5a1b3Sopenharmony_ci            pa_sink_update_status(i->sink);
82053a5a1b3Sopenharmony_ci
82153a5a1b3Sopenharmony_ci        i->sink = NULL;
82253a5a1b3Sopenharmony_ci    }
82353a5a1b3Sopenharmony_ci
82453a5a1b3Sopenharmony_ci    if (linked) {
82553a5a1b3Sopenharmony_ci        pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_REMOVE, i->index);
82653a5a1b3Sopenharmony_ci        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i);
82753a5a1b3Sopenharmony_ci    }
82853a5a1b3Sopenharmony_ci
82953a5a1b3Sopenharmony_ci    pa_core_maybe_vacuum(i->core);
83053a5a1b3Sopenharmony_ci
83153a5a1b3Sopenharmony_ci    pa_sink_input_unref(i);
83253a5a1b3Sopenharmony_ci}
83353a5a1b3Sopenharmony_ci
83453a5a1b3Sopenharmony_ci/* Called from main context */
83553a5a1b3Sopenharmony_cistatic void sink_input_free(pa_object *o) {
83653a5a1b3Sopenharmony_ci    pa_sink_input* i = PA_SINK_INPUT(o);
83753a5a1b3Sopenharmony_ci
83853a5a1b3Sopenharmony_ci    pa_assert(i);
83953a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
84053a5a1b3Sopenharmony_ci    pa_assert(pa_sink_input_refcnt(i) == 0);
84153a5a1b3Sopenharmony_ci    pa_assert(!PA_SINK_INPUT_IS_LINKED(i->state));
84253a5a1b3Sopenharmony_ci
84353a5a1b3Sopenharmony_ci    pa_log_info("Freeing input %u \"%s\"", i->index,
84453a5a1b3Sopenharmony_ci                i->proplist ? pa_strnull(pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME)) : "");
84553a5a1b3Sopenharmony_ci
84653a5a1b3Sopenharmony_ci    /* Side note: this function must be able to destruct properly any
84753a5a1b3Sopenharmony_ci     * kind of sink input in any state, even those which are
84853a5a1b3Sopenharmony_ci     * "half-moved" or are connected to sinks that have no asyncmsgq
84953a5a1b3Sopenharmony_ci     * and are hence half-destructed themselves! */
85053a5a1b3Sopenharmony_ci
85153a5a1b3Sopenharmony_ci    if (i->thread_info.render_memblockq)
85253a5a1b3Sopenharmony_ci        pa_memblockq_free(i->thread_info.render_memblockq);
85353a5a1b3Sopenharmony_ci
85453a5a1b3Sopenharmony_ci    if (i->thread_info.history_memblockq)
85553a5a1b3Sopenharmony_ci        pa_memblockq_free(i->thread_info.history_memblockq);
85653a5a1b3Sopenharmony_ci
85753a5a1b3Sopenharmony_ci    if (i->thread_info.resampler)
85853a5a1b3Sopenharmony_ci        pa_resampler_free(i->thread_info.resampler);
85953a5a1b3Sopenharmony_ci
86053a5a1b3Sopenharmony_ci    if (i->format)
86153a5a1b3Sopenharmony_ci        pa_format_info_free(i->format);
86253a5a1b3Sopenharmony_ci
86353a5a1b3Sopenharmony_ci    if (i->proplist)
86453a5a1b3Sopenharmony_ci        pa_proplist_free(i->proplist);
86553a5a1b3Sopenharmony_ci
86653a5a1b3Sopenharmony_ci    if (i->direct_outputs)
86753a5a1b3Sopenharmony_ci        pa_idxset_free(i->direct_outputs, NULL);
86853a5a1b3Sopenharmony_ci
86953a5a1b3Sopenharmony_ci    if (i->thread_info.direct_outputs)
87053a5a1b3Sopenharmony_ci        pa_hashmap_free(i->thread_info.direct_outputs);
87153a5a1b3Sopenharmony_ci
87253a5a1b3Sopenharmony_ci    if (i->volume_factor_items)
87353a5a1b3Sopenharmony_ci        pa_hashmap_free(i->volume_factor_items);
87453a5a1b3Sopenharmony_ci
87553a5a1b3Sopenharmony_ci    if (i->volume_factor_sink_items)
87653a5a1b3Sopenharmony_ci        pa_hashmap_free(i->volume_factor_sink_items);
87753a5a1b3Sopenharmony_ci
87853a5a1b3Sopenharmony_ci    if (i->preferred_sink)
87953a5a1b3Sopenharmony_ci        pa_xfree(i->preferred_sink);
88053a5a1b3Sopenharmony_ci
88153a5a1b3Sopenharmony_ci    pa_xfree(i->driver);
88253a5a1b3Sopenharmony_ci    pa_xfree(i);
88353a5a1b3Sopenharmony_ci}
88453a5a1b3Sopenharmony_ci
88553a5a1b3Sopenharmony_ci/* Called from main context */
88653a5a1b3Sopenharmony_civoid pa_sink_input_put(pa_sink_input *i) {
88753a5a1b3Sopenharmony_ci    pa_sink_input_state_t state;
88853a5a1b3Sopenharmony_ci
88953a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
89053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
89153a5a1b3Sopenharmony_ci
89253a5a1b3Sopenharmony_ci    pa_assert(i->state == PA_SINK_INPUT_INIT);
89353a5a1b3Sopenharmony_ci
89453a5a1b3Sopenharmony_ci    /* The following fields must be initialized properly */
89553a5a1b3Sopenharmony_ci    pa_assert(i->pop);
89653a5a1b3Sopenharmony_ci    pa_assert(i->process_rewind);
89753a5a1b3Sopenharmony_ci    pa_assert(i->kill);
89853a5a1b3Sopenharmony_ci
89953a5a1b3Sopenharmony_ci    state = i->flags & PA_SINK_INPUT_START_CORKED ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
90053a5a1b3Sopenharmony_ci
90153a5a1b3Sopenharmony_ci    update_n_corked(i, state);
90253a5a1b3Sopenharmony_ci    i->state = state;
90353a5a1b3Sopenharmony_ci
90453a5a1b3Sopenharmony_ci    /* We might need to update the sink's volume if we are in flat volume mode. */
90553a5a1b3Sopenharmony_ci    if (pa_sink_flat_volume_enabled(i->sink))
90653a5a1b3Sopenharmony_ci        pa_sink_set_volume(i->sink, NULL, false, i->save_volume);
90753a5a1b3Sopenharmony_ci    else {
90853a5a1b3Sopenharmony_ci        if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
90953a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_is_norm(&i->volume));
91053a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_is_norm(&i->reference_ratio));
91153a5a1b3Sopenharmony_ci        }
91253a5a1b3Sopenharmony_ci
91353a5a1b3Sopenharmony_ci        set_real_ratio(i, &i->volume);
91453a5a1b3Sopenharmony_ci    }
91553a5a1b3Sopenharmony_ci
91653a5a1b3Sopenharmony_ci    if (pa_sink_input_is_passthrough(i))
91753a5a1b3Sopenharmony_ci        pa_sink_enter_passthrough(i->sink);
91853a5a1b3Sopenharmony_ci
91953a5a1b3Sopenharmony_ci    i->thread_info.soft_volume = i->soft_volume;
92053a5a1b3Sopenharmony_ci    i->thread_info.muted = i->muted;
92153a5a1b3Sopenharmony_ci
92253a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_ADD_INPUT, i, 0, NULL) == 0);
92353a5a1b3Sopenharmony_ci
92453a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index);
92553a5a1b3Sopenharmony_ci    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i);
92653a5a1b3Sopenharmony_ci
92753a5a1b3Sopenharmony_ci    pa_sink_update_status(i->sink);
92853a5a1b3Sopenharmony_ci}
92953a5a1b3Sopenharmony_ci
93053a5a1b3Sopenharmony_ci/* Called from main context */
93153a5a1b3Sopenharmony_civoid pa_sink_input_kill(pa_sink_input*i) {
93253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
93353a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
93453a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
93553a5a1b3Sopenharmony_ci
93653a5a1b3Sopenharmony_ci    i->kill(i);
93753a5a1b3Sopenharmony_ci}
93853a5a1b3Sopenharmony_ci
93953a5a1b3Sopenharmony_ci/* Called from main context */
94053a5a1b3Sopenharmony_cipa_usec_t pa_sink_input_get_latency(pa_sink_input *i, pa_usec_t *sink_latency) {
94153a5a1b3Sopenharmony_ci    pa_usec_t r[2] = { 0, 0 };
94253a5a1b3Sopenharmony_ci
94353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
94453a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
94553a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
94653a5a1b3Sopenharmony_ci
94753a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_LATENCY, r, 0, NULL) == 0);
94853a5a1b3Sopenharmony_ci
94953a5a1b3Sopenharmony_ci    if (i->get_latency)
95053a5a1b3Sopenharmony_ci        r[0] += i->get_latency(i);
95153a5a1b3Sopenharmony_ci
95253a5a1b3Sopenharmony_ci    if (sink_latency)
95353a5a1b3Sopenharmony_ci        *sink_latency = r[1];
95453a5a1b3Sopenharmony_ci
95553a5a1b3Sopenharmony_ci    return r[0];
95653a5a1b3Sopenharmony_ci}
95753a5a1b3Sopenharmony_ci
95853a5a1b3Sopenharmony_ci/* Called from thread context */
95953a5a1b3Sopenharmony_civoid pa_sink_input_peek(pa_sink_input *i, size_t slength /* in sink bytes */, pa_memchunk *chunk, pa_cvolume *volume) {
96053a5a1b3Sopenharmony_ci    bool do_volume_adj_here, need_volume_factor_sink;
96153a5a1b3Sopenharmony_ci    bool volume_is_norm;
96253a5a1b3Sopenharmony_ci    size_t block_size_max_sink, block_size_max_sink_input;
96353a5a1b3Sopenharmony_ci    size_t ilength;
96453a5a1b3Sopenharmony_ci    size_t ilength_full;
96553a5a1b3Sopenharmony_ci
96653a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
96753a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
96853a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
96953a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(slength, &i->sink->sample_spec));
97053a5a1b3Sopenharmony_ci    pa_assert(chunk);
97153a5a1b3Sopenharmony_ci    pa_assert(volume);
97253a5a1b3Sopenharmony_ci
97353a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
97453a5a1b3Sopenharmony_ci    pa_log_debug("peek");
97553a5a1b3Sopenharmony_ci#endif
97653a5a1b3Sopenharmony_ci
97753a5a1b3Sopenharmony_ci    block_size_max_sink_input = i->thread_info.resampler ?
97853a5a1b3Sopenharmony_ci        pa_resampler_max_block_size(i->thread_info.resampler) :
97953a5a1b3Sopenharmony_ci        pa_frame_align(pa_mempool_block_size_max(i->core->mempool), &i->sample_spec);
98053a5a1b3Sopenharmony_ci
98153a5a1b3Sopenharmony_ci    block_size_max_sink = pa_frame_align(pa_mempool_block_size_max(i->core->mempool), &i->sink->sample_spec);
98253a5a1b3Sopenharmony_ci
98353a5a1b3Sopenharmony_ci    /* Default buffer size */
98453a5a1b3Sopenharmony_ci    if (slength <= 0)
98553a5a1b3Sopenharmony_ci        slength = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sink->sample_spec);
98653a5a1b3Sopenharmony_ci
98753a5a1b3Sopenharmony_ci    if (slength > block_size_max_sink)
98853a5a1b3Sopenharmony_ci        slength = block_size_max_sink;
98953a5a1b3Sopenharmony_ci
99053a5a1b3Sopenharmony_ci    if (i->thread_info.resampler) {
99153a5a1b3Sopenharmony_ci        ilength = pa_resampler_request(i->thread_info.resampler, slength);
99253a5a1b3Sopenharmony_ci
99353a5a1b3Sopenharmony_ci        if (ilength <= 0)
99453a5a1b3Sopenharmony_ci            ilength = pa_frame_align(CONVERT_BUFFER_LENGTH, &i->sample_spec);
99553a5a1b3Sopenharmony_ci    } else
99653a5a1b3Sopenharmony_ci        ilength = slength;
99753a5a1b3Sopenharmony_ci
99853a5a1b3Sopenharmony_ci    /* Length corresponding to slength (without limiting to
99953a5a1b3Sopenharmony_ci     * block_size_max_sink_input). */
100053a5a1b3Sopenharmony_ci    ilength_full = ilength;
100153a5a1b3Sopenharmony_ci
100253a5a1b3Sopenharmony_ci    if (ilength > block_size_max_sink_input)
100353a5a1b3Sopenharmony_ci        ilength = block_size_max_sink_input;
100453a5a1b3Sopenharmony_ci
100553a5a1b3Sopenharmony_ci    /* If the channel maps of the sink and this stream differ, we need
100653a5a1b3Sopenharmony_ci     * to adjust the volume *before* we resample. Otherwise we can do
100753a5a1b3Sopenharmony_ci     * it after and leave it for the sink code */
100853a5a1b3Sopenharmony_ci
100953a5a1b3Sopenharmony_ci    do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
101053a5a1b3Sopenharmony_ci    volume_is_norm = pa_cvolume_is_norm(&i->thread_info.soft_volume) && !i->thread_info.muted;
101153a5a1b3Sopenharmony_ci    need_volume_factor_sink = !pa_cvolume_is_norm(&i->volume_factor_sink);
101253a5a1b3Sopenharmony_ci
101353a5a1b3Sopenharmony_ci    while (!pa_memblockq_is_readable(i->thread_info.render_memblockq)) {
101453a5a1b3Sopenharmony_ci        pa_memchunk tchunk;
101553a5a1b3Sopenharmony_ci
101653a5a1b3Sopenharmony_ci        /* There's nothing in our render queue. We need to fill it up
101753a5a1b3Sopenharmony_ci         * with data from the implementor. */
101853a5a1b3Sopenharmony_ci
101953a5a1b3Sopenharmony_ci        if (i->thread_info.state == PA_SINK_INPUT_CORKED ||
102053a5a1b3Sopenharmony_ci            i->pop(i, ilength, &tchunk) < 0) {
102153a5a1b3Sopenharmony_ci
102253a5a1b3Sopenharmony_ci            /* OK, we're corked or the implementor didn't give us any
102353a5a1b3Sopenharmony_ci             * data, so let's just hand out silence */
102453a5a1b3Sopenharmony_ci
102553a5a1b3Sopenharmony_ci            pa_memblockq_seek(i->thread_info.render_memblockq, (int64_t) slength, PA_SEEK_RELATIVE, true);
102653a5a1b3Sopenharmony_ci            pa_memblockq_seek(i->thread_info.history_memblockq, (int64_t) ilength_full, PA_SEEK_RELATIVE, true);
102753a5a1b3Sopenharmony_ci            i->thread_info.playing_for = 0;
102853a5a1b3Sopenharmony_ci            if (i->thread_info.underrun_for != (uint64_t) -1) {
102953a5a1b3Sopenharmony_ci                i->thread_info.underrun_for += ilength_full;
103053a5a1b3Sopenharmony_ci                i->thread_info.underrun_for_sink += slength;
103153a5a1b3Sopenharmony_ci            }
103253a5a1b3Sopenharmony_ci            break;
103353a5a1b3Sopenharmony_ci        }
103453a5a1b3Sopenharmony_ci
103553a5a1b3Sopenharmony_ci        pa_assert(tchunk.length > 0);
103653a5a1b3Sopenharmony_ci        pa_assert(tchunk.memblock);
103753a5a1b3Sopenharmony_ci
103853a5a1b3Sopenharmony_ci        i->thread_info.underrun_for = 0;
103953a5a1b3Sopenharmony_ci        i->thread_info.underrun_for_sink = 0;
104053a5a1b3Sopenharmony_ci        i->thread_info.playing_for += tchunk.length;
104153a5a1b3Sopenharmony_ci
104253a5a1b3Sopenharmony_ci        while (tchunk.length > 0) {
104353a5a1b3Sopenharmony_ci            pa_memchunk wchunk;
104453a5a1b3Sopenharmony_ci            bool nvfs = need_volume_factor_sink;
104553a5a1b3Sopenharmony_ci
104653a5a1b3Sopenharmony_ci            wchunk = tchunk;
104753a5a1b3Sopenharmony_ci            pa_memblock_ref(wchunk.memblock);
104853a5a1b3Sopenharmony_ci
104953a5a1b3Sopenharmony_ci            if (wchunk.length > block_size_max_sink_input)
105053a5a1b3Sopenharmony_ci                wchunk.length = block_size_max_sink_input;
105153a5a1b3Sopenharmony_ci
105253a5a1b3Sopenharmony_ci            /* It might be necessary to adjust the volume here */
105353a5a1b3Sopenharmony_ci            if (do_volume_adj_here && !volume_is_norm) {
105453a5a1b3Sopenharmony_ci                pa_memchunk_make_writable(&wchunk, 0);
105553a5a1b3Sopenharmony_ci
105653a5a1b3Sopenharmony_ci                if (i->thread_info.muted) {
105753a5a1b3Sopenharmony_ci                    pa_silence_memchunk(&wchunk, &i->thread_info.sample_spec);
105853a5a1b3Sopenharmony_ci                    nvfs = false;
105953a5a1b3Sopenharmony_ci
106053a5a1b3Sopenharmony_ci                } else if (!i->thread_info.resampler && nvfs) {
106153a5a1b3Sopenharmony_ci                    pa_cvolume v;
106253a5a1b3Sopenharmony_ci
106353a5a1b3Sopenharmony_ci                    /* If we don't need a resampler we can merge the
106453a5a1b3Sopenharmony_ci                     * post and the pre volume adjustment into one */
106553a5a1b3Sopenharmony_ci
106653a5a1b3Sopenharmony_ci                    pa_sw_cvolume_multiply(&v, &i->thread_info.soft_volume, &i->volume_factor_sink);
106753a5a1b3Sopenharmony_ci                    pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &v);
106853a5a1b3Sopenharmony_ci                    nvfs = false;
106953a5a1b3Sopenharmony_ci
107053a5a1b3Sopenharmony_ci                } else
107153a5a1b3Sopenharmony_ci                    pa_volume_memchunk(&wchunk, &i->thread_info.sample_spec, &i->thread_info.soft_volume);
107253a5a1b3Sopenharmony_ci            }
107353a5a1b3Sopenharmony_ci
107453a5a1b3Sopenharmony_ci            /* Push chunk into history queue to retain some resampler input history. */
107553a5a1b3Sopenharmony_ci            pa_memblockq_push(i->thread_info.history_memblockq, &wchunk);
107653a5a1b3Sopenharmony_ci
107753a5a1b3Sopenharmony_ci            if (!i->thread_info.resampler) {
107853a5a1b3Sopenharmony_ci
107953a5a1b3Sopenharmony_ci                if (nvfs) {
108053a5a1b3Sopenharmony_ci                    pa_memchunk_make_writable(&wchunk, 0);
108153a5a1b3Sopenharmony_ci                    pa_volume_memchunk(&wchunk, &i->sink->sample_spec, &i->volume_factor_sink);
108253a5a1b3Sopenharmony_ci                }
108353a5a1b3Sopenharmony_ci
108453a5a1b3Sopenharmony_ci                pa_memblockq_push_align(i->thread_info.render_memblockq, &wchunk);
108553a5a1b3Sopenharmony_ci            } else {
108653a5a1b3Sopenharmony_ci                pa_memchunk rchunk;
108753a5a1b3Sopenharmony_ci                pa_resampler_run(i->thread_info.resampler, &wchunk, &rchunk);
108853a5a1b3Sopenharmony_ci
108953a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
109053a5a1b3Sopenharmony_ci                pa_log_debug("pushing %lu", (unsigned long) rchunk.length);
109153a5a1b3Sopenharmony_ci#endif
109253a5a1b3Sopenharmony_ci
109353a5a1b3Sopenharmony_ci                if (rchunk.memblock) {
109453a5a1b3Sopenharmony_ci
109553a5a1b3Sopenharmony_ci                    if (nvfs) {
109653a5a1b3Sopenharmony_ci                        pa_memchunk_make_writable(&rchunk, 0);
109753a5a1b3Sopenharmony_ci                        pa_volume_memchunk(&rchunk, &i->sink->sample_spec, &i->volume_factor_sink);
109853a5a1b3Sopenharmony_ci                    }
109953a5a1b3Sopenharmony_ci
110053a5a1b3Sopenharmony_ci                    pa_memblockq_push_align(i->thread_info.render_memblockq, &rchunk);
110153a5a1b3Sopenharmony_ci                    pa_memblock_unref(rchunk.memblock);
110253a5a1b3Sopenharmony_ci                }
110353a5a1b3Sopenharmony_ci            }
110453a5a1b3Sopenharmony_ci
110553a5a1b3Sopenharmony_ci            pa_memblock_unref(wchunk.memblock);
110653a5a1b3Sopenharmony_ci
110753a5a1b3Sopenharmony_ci            tchunk.index += wchunk.length;
110853a5a1b3Sopenharmony_ci            tchunk.length -= wchunk.length;
110953a5a1b3Sopenharmony_ci        }
111053a5a1b3Sopenharmony_ci
111153a5a1b3Sopenharmony_ci        pa_memblock_unref(tchunk.memblock);
111253a5a1b3Sopenharmony_ci    }
111353a5a1b3Sopenharmony_ci
111453a5a1b3Sopenharmony_ci    pa_assert_se(pa_memblockq_peek(i->thread_info.render_memblockq, chunk) >= 0);
111553a5a1b3Sopenharmony_ci
111653a5a1b3Sopenharmony_ci    pa_assert(chunk->length > 0);
111753a5a1b3Sopenharmony_ci    pa_assert(chunk->memblock);
111853a5a1b3Sopenharmony_ci
111953a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
112053a5a1b3Sopenharmony_ci    pa_log_debug("peeking %lu", (unsigned long) chunk->length);
112153a5a1b3Sopenharmony_ci#endif
112253a5a1b3Sopenharmony_ci
112353a5a1b3Sopenharmony_ci    if (chunk->length > block_size_max_sink)
112453a5a1b3Sopenharmony_ci        chunk->length = block_size_max_sink;
112553a5a1b3Sopenharmony_ci
112653a5a1b3Sopenharmony_ci    /* Let's see if we had to apply the volume adjustment ourselves,
112753a5a1b3Sopenharmony_ci     * or if this can be done by the sink for us */
112853a5a1b3Sopenharmony_ci
112953a5a1b3Sopenharmony_ci    if (do_volume_adj_here)
113053a5a1b3Sopenharmony_ci        /* We had different channel maps, so we already did the adjustment */
113153a5a1b3Sopenharmony_ci        pa_cvolume_reset(volume, i->sink->sample_spec.channels);
113253a5a1b3Sopenharmony_ci    else if (i->thread_info.muted)
113353a5a1b3Sopenharmony_ci        /* We've both the same channel map, so let's have the sink do the adjustment for us*/
113453a5a1b3Sopenharmony_ci        pa_cvolume_mute(volume, i->sink->sample_spec.channels);
113553a5a1b3Sopenharmony_ci    else
113653a5a1b3Sopenharmony_ci        *volume = i->thread_info.soft_volume;
113753a5a1b3Sopenharmony_ci}
113853a5a1b3Sopenharmony_ci
113953a5a1b3Sopenharmony_ci/* Called from thread context */
114053a5a1b3Sopenharmony_civoid pa_sink_input_drop(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
114153a5a1b3Sopenharmony_ci    int64_t rbq, hbq;
114253a5a1b3Sopenharmony_ci
114353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
114453a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
114553a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
114653a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
114753a5a1b3Sopenharmony_ci    pa_assert(nbytes > 0);
114853a5a1b3Sopenharmony_ci
114953a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
115053a5a1b3Sopenharmony_ci    pa_log_debug("dropping %lu", (unsigned long) nbytes);
115153a5a1b3Sopenharmony_ci#endif
115253a5a1b3Sopenharmony_ci
115353a5a1b3Sopenharmony_ci    pa_memblockq_drop(i->thread_info.render_memblockq, nbytes);
115453a5a1b3Sopenharmony_ci
115553a5a1b3Sopenharmony_ci    /* Keep memblockq's in sync. Using pa_resampler_request()
115653a5a1b3Sopenharmony_ci     * on nbytes will not work here because of rounding. */
115753a5a1b3Sopenharmony_ci    rbq = pa_memblockq_get_write_index(i->thread_info.render_memblockq);
115853a5a1b3Sopenharmony_ci    rbq -= pa_memblockq_get_read_index(i->thread_info.render_memblockq);
115953a5a1b3Sopenharmony_ci    hbq = pa_memblockq_get_write_index(i->thread_info.history_memblockq);
116053a5a1b3Sopenharmony_ci    hbq -= pa_memblockq_get_read_index(i->thread_info.history_memblockq);
116153a5a1b3Sopenharmony_ci    if (rbq >= 0)
116253a5a1b3Sopenharmony_ci        rbq = pa_resampler_request(i->thread_info.resampler, rbq);
116353a5a1b3Sopenharmony_ci    else
116453a5a1b3Sopenharmony_ci        rbq = - (int64_t) pa_resampler_request(i->thread_info.resampler, - rbq);
116553a5a1b3Sopenharmony_ci
116653a5a1b3Sopenharmony_ci    if (hbq > rbq)
116753a5a1b3Sopenharmony_ci        pa_memblockq_drop(i->thread_info.history_memblockq, hbq - rbq);
116853a5a1b3Sopenharmony_ci    else if (rbq > hbq)
116953a5a1b3Sopenharmony_ci        pa_memblockq_rewind(i->thread_info.history_memblockq, rbq - hbq);
117053a5a1b3Sopenharmony_ci}
117153a5a1b3Sopenharmony_ci
117253a5a1b3Sopenharmony_ci/* Called from thread context */
117353a5a1b3Sopenharmony_cibool pa_sink_input_process_underrun(pa_sink_input *i) {
117453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
117553a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
117653a5a1b3Sopenharmony_ci
117753a5a1b3Sopenharmony_ci    if (pa_memblockq_is_readable(i->thread_info.render_memblockq))
117853a5a1b3Sopenharmony_ci        return false;
117953a5a1b3Sopenharmony_ci
118053a5a1b3Sopenharmony_ci    if (i->process_underrun && i->process_underrun(i)) {
118153a5a1b3Sopenharmony_ci        /* All valid data has been played back, so we can empty this queue. */
118253a5a1b3Sopenharmony_ci        pa_memblockq_silence(i->thread_info.render_memblockq);
118353a5a1b3Sopenharmony_ci        pa_memblockq_silence(i->thread_info.history_memblockq);
118453a5a1b3Sopenharmony_ci        return true;
118553a5a1b3Sopenharmony_ci    }
118653a5a1b3Sopenharmony_ci    return false;
118753a5a1b3Sopenharmony_ci}
118853a5a1b3Sopenharmony_ci
118953a5a1b3Sopenharmony_ci/* Called from thread context */
119053a5a1b3Sopenharmony_civoid pa_sink_input_process_rewind(pa_sink_input *i, size_t nbytes /* in sink sample spec */) {
119153a5a1b3Sopenharmony_ci    size_t lbq;
119253a5a1b3Sopenharmony_ci    bool called = false;
119353a5a1b3Sopenharmony_ci    size_t sink_input_nbytes;
119453a5a1b3Sopenharmony_ci
119553a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
119653a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
119753a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
119853a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
119953a5a1b3Sopenharmony_ci
120053a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
120153a5a1b3Sopenharmony_ci    pa_log_debug("rewind(%lu, %lu)", (unsigned long) nbytes, (unsigned long) i->thread_info.rewrite_nbytes);
120253a5a1b3Sopenharmony_ci#endif
120353a5a1b3Sopenharmony_ci
120453a5a1b3Sopenharmony_ci    lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
120553a5a1b3Sopenharmony_ci    sink_input_nbytes = pa_resampler_request(i->thread_info.resampler, nbytes);
120653a5a1b3Sopenharmony_ci
120753a5a1b3Sopenharmony_ci    if (nbytes > 0 && !i->thread_info.dont_rewind_render) {
120853a5a1b3Sopenharmony_ci        pa_log_debug("Have to rewind %lu bytes on render memblockq.", (unsigned long) nbytes);
120953a5a1b3Sopenharmony_ci        pa_memblockq_rewind(i->thread_info.render_memblockq, nbytes);
121053a5a1b3Sopenharmony_ci        pa_memblockq_rewind(i->thread_info.history_memblockq, sink_input_nbytes);
121153a5a1b3Sopenharmony_ci    }
121253a5a1b3Sopenharmony_ci
121353a5a1b3Sopenharmony_ci    if (i->thread_info.dont_rewrite)
121453a5a1b3Sopenharmony_ci        goto finish;
121553a5a1b3Sopenharmony_ci
121653a5a1b3Sopenharmony_ci    if (i->thread_info.rewrite_nbytes == (size_t) -1) {
121753a5a1b3Sopenharmony_ci
121853a5a1b3Sopenharmony_ci        /* We were asked to drop all buffered data, and rerequest new
121953a5a1b3Sopenharmony_ci         * data from implementor the next time peek() is called */
122053a5a1b3Sopenharmony_ci
122153a5a1b3Sopenharmony_ci        pa_memblockq_flush_write(i->thread_info.render_memblockq, true);
122253a5a1b3Sopenharmony_ci        pa_memblockq_flush_write(i->thread_info.history_memblockq, true);
122353a5a1b3Sopenharmony_ci
122453a5a1b3Sopenharmony_ci    } else if (i->thread_info.rewrite_nbytes > 0) {
122553a5a1b3Sopenharmony_ci        size_t max_rewrite, sink_amount, sink_input_amount;
122653a5a1b3Sopenharmony_ci
122753a5a1b3Sopenharmony_ci        /* Calculate how much make sense to rewrite at most */
122853a5a1b3Sopenharmony_ci        max_rewrite = nbytes;
122953a5a1b3Sopenharmony_ci        if (nbytes > 0)
123053a5a1b3Sopenharmony_ci            max_rewrite += lbq;
123153a5a1b3Sopenharmony_ci
123253a5a1b3Sopenharmony_ci        /* Transform into local domain */
123353a5a1b3Sopenharmony_ci        sink_input_amount = pa_resampler_request(i->thread_info.resampler, max_rewrite);
123453a5a1b3Sopenharmony_ci
123553a5a1b3Sopenharmony_ci        /* Calculate how much of the rewinded data should actually be rewritten */
123653a5a1b3Sopenharmony_ci        sink_input_amount = PA_MIN(i->thread_info.rewrite_nbytes, sink_input_amount);
123753a5a1b3Sopenharmony_ci
123853a5a1b3Sopenharmony_ci        /* Transform to sink domain */
123953a5a1b3Sopenharmony_ci        sink_amount = pa_resampler_result(i->thread_info.resampler, sink_input_amount);
124053a5a1b3Sopenharmony_ci
124153a5a1b3Sopenharmony_ci        if (sink_input_amount > 0) {
124253a5a1b3Sopenharmony_ci            pa_log_debug("Have to rewind %lu bytes on implementor.", (unsigned long) sink_input_amount);
124353a5a1b3Sopenharmony_ci
124453a5a1b3Sopenharmony_ci            /* Tell the implementor */
124553a5a1b3Sopenharmony_ci            if (i->process_rewind)
124653a5a1b3Sopenharmony_ci                i->process_rewind(i, sink_input_amount);
124753a5a1b3Sopenharmony_ci            called = true;
124853a5a1b3Sopenharmony_ci
124953a5a1b3Sopenharmony_ci            /* Update the write pointer. Use pa_resampler_result(r, sink_input_amount) instead
125053a5a1b3Sopenharmony_ci             * of sink_amount because the two may differ and the actual replay of the samples
125153a5a1b3Sopenharmony_ci             * will produce pa_resampler_result(r, sink_input_amount) samples. */
125253a5a1b3Sopenharmony_ci            pa_memblockq_seek(i->thread_info.render_memblockq, - ((int64_t) pa_resampler_result(i->thread_info.resampler, sink_input_amount)),PA_SEEK_RELATIVE, true);
125353a5a1b3Sopenharmony_ci
125453a5a1b3Sopenharmony_ci            /* Rewind the resampler */
125553a5a1b3Sopenharmony_ci            if (i->thread_info.resampler) {
125653a5a1b3Sopenharmony_ci                size_t history_bytes;
125753a5a1b3Sopenharmony_ci                int64_t history_result;
125853a5a1b3Sopenharmony_ci
125953a5a1b3Sopenharmony_ci                history_bytes = calculate_resampler_history_bytes(i, sink_input_amount / pa_frame_size(&i->sample_spec));
126053a5a1b3Sopenharmony_ci
126153a5a1b3Sopenharmony_ci               if (history_bytes > 0) {
126253a5a1b3Sopenharmony_ci                    history_result = pa_resampler_rewind(i->thread_info.resampler, sink_amount, i->thread_info.history_memblockq, history_bytes);
126353a5a1b3Sopenharmony_ci
126453a5a1b3Sopenharmony_ci                    /* We may have produced one sample too much or or one sample less than expected.
126553a5a1b3Sopenharmony_ci                     * The replay of the rewound sink input data will then produce a deviation in
126653a5a1b3Sopenharmony_ci                     * the other direction, so that the total number of produced samples matches
126753a5a1b3Sopenharmony_ci                     * pa_resampler_result(r, sink_input_amount + history_bytes). Therefore we have
126853a5a1b3Sopenharmony_ci                     * to correct the write pointer of the render queue accordingly.
126953a5a1b3Sopenharmony_ci                     * Strictly this is only true, if the history can be replayed from a known
127053a5a1b3Sopenharmony_ci                     * resampler state, that is if a true matching period exists. In case where
127153a5a1b3Sopenharmony_ci                     * we are using an approximate matching period, we may still loose or duplicate
127253a5a1b3Sopenharmony_ci                     * one sample during rewind. */
127353a5a1b3Sopenharmony_ci                    history_result -= (int64_t) pa_resampler_result(i->thread_info.resampler, history_bytes);
127453a5a1b3Sopenharmony_ci                    if (history_result != 0)
127553a5a1b3Sopenharmony_ci                        pa_memblockq_seek(i->thread_info.render_memblockq, history_result, PA_SEEK_RELATIVE, true);
127653a5a1b3Sopenharmony_ci                }
127753a5a1b3Sopenharmony_ci            }
127853a5a1b3Sopenharmony_ci
127953a5a1b3Sopenharmony_ci            /* Update the history write pointer */
128053a5a1b3Sopenharmony_ci            pa_memblockq_seek(i->thread_info.history_memblockq, - ((int64_t) sink_input_amount), PA_SEEK_RELATIVE, true);
128153a5a1b3Sopenharmony_ci
128253a5a1b3Sopenharmony_ci            if (i->thread_info.rewrite_flush) {
128353a5a1b3Sopenharmony_ci                pa_memblockq_silence(i->thread_info.render_memblockq);
128453a5a1b3Sopenharmony_ci                pa_memblockq_silence(i->thread_info.history_memblockq);
128553a5a1b3Sopenharmony_ci            }
128653a5a1b3Sopenharmony_ci        }
128753a5a1b3Sopenharmony_ci    }
128853a5a1b3Sopenharmony_ci
128953a5a1b3Sopenharmony_cifinish:
129053a5a1b3Sopenharmony_ci    if (!called)
129153a5a1b3Sopenharmony_ci        if (i->process_rewind)
129253a5a1b3Sopenharmony_ci            i->process_rewind(i, 0);
129353a5a1b3Sopenharmony_ci
129453a5a1b3Sopenharmony_ci    i->thread_info.dont_rewrite = false;
129553a5a1b3Sopenharmony_ci    i->thread_info.rewrite_nbytes = 0;
129653a5a1b3Sopenharmony_ci    i->thread_info.rewrite_flush = false;
129753a5a1b3Sopenharmony_ci    i->thread_info.dont_rewind_render = false;
129853a5a1b3Sopenharmony_ci}
129953a5a1b3Sopenharmony_ci
130053a5a1b3Sopenharmony_ci/* Called from thread context */
130153a5a1b3Sopenharmony_cisize_t pa_sink_input_get_max_rewind(pa_sink_input *i) {
130253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
130353a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
130453a5a1b3Sopenharmony_ci
130553a5a1b3Sopenharmony_ci    return pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_rewind);
130653a5a1b3Sopenharmony_ci}
130753a5a1b3Sopenharmony_ci
130853a5a1b3Sopenharmony_ci/* Called from thread context */
130953a5a1b3Sopenharmony_cisize_t pa_sink_input_get_max_request(pa_sink_input *i) {
131053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
131153a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
131253a5a1b3Sopenharmony_ci
131353a5a1b3Sopenharmony_ci    /* We're not verifying the status here, to allow this to be called
131453a5a1b3Sopenharmony_ci     * in the state change handler between _INIT and _RUNNING */
131553a5a1b3Sopenharmony_ci
131653a5a1b3Sopenharmony_ci    return pa_resampler_request(i->thread_info.resampler, i->sink->thread_info.max_request);
131753a5a1b3Sopenharmony_ci}
131853a5a1b3Sopenharmony_ci
131953a5a1b3Sopenharmony_ci/* Called from thread context */
132053a5a1b3Sopenharmony_civoid pa_sink_input_update_max_rewind(pa_sink_input *i, size_t nbytes  /* in the sink's sample spec */) {
132153a5a1b3Sopenharmony_ci    size_t max_rewind;
132253a5a1b3Sopenharmony_ci    size_t resampler_history;
132353a5a1b3Sopenharmony_ci
132453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
132553a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
132653a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
132753a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
132853a5a1b3Sopenharmony_ci
132953a5a1b3Sopenharmony_ci    pa_memblockq_set_maxrewind(i->thread_info.render_memblockq, nbytes);
133053a5a1b3Sopenharmony_ci
133153a5a1b3Sopenharmony_ci    max_rewind = pa_resampler_request(i->thread_info.resampler, nbytes);
133253a5a1b3Sopenharmony_ci    /* Calculate maximum history needed */
133353a5a1b3Sopenharmony_ci    resampler_history = pa_resampler_get_max_history(i->thread_info.resampler);
133453a5a1b3Sopenharmony_ci    resampler_history *= pa_frame_size(&i->sample_spec);
133553a5a1b3Sopenharmony_ci
133653a5a1b3Sopenharmony_ci    pa_memblockq_set_maxrewind(i->thread_info.history_memblockq, max_rewind + resampler_history);
133753a5a1b3Sopenharmony_ci
133853a5a1b3Sopenharmony_ci    if (i->update_max_rewind)
133953a5a1b3Sopenharmony_ci        i->update_max_rewind(i, max_rewind);
134053a5a1b3Sopenharmony_ci}
134153a5a1b3Sopenharmony_ci
134253a5a1b3Sopenharmony_ci/* Called from thread context */
134353a5a1b3Sopenharmony_civoid pa_sink_input_update_max_request(pa_sink_input *i, size_t nbytes  /* in the sink's sample spec */) {
134453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
134553a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
134653a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->thread_info.state));
134753a5a1b3Sopenharmony_ci    pa_assert(pa_frame_aligned(nbytes, &i->sink->sample_spec));
134853a5a1b3Sopenharmony_ci
134953a5a1b3Sopenharmony_ci    if (i->update_max_request)
135053a5a1b3Sopenharmony_ci        i->update_max_request(i, pa_resampler_request(i->thread_info.resampler, nbytes));
135153a5a1b3Sopenharmony_ci}
135253a5a1b3Sopenharmony_ci
135353a5a1b3Sopenharmony_ci/* Called from thread context */
135453a5a1b3Sopenharmony_cipa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
135553a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
135653a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
135753a5a1b3Sopenharmony_ci
135853a5a1b3Sopenharmony_ci    if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
135953a5a1b3Sopenharmony_ci        usec = i->sink->thread_info.fixed_latency;
136053a5a1b3Sopenharmony_ci
136153a5a1b3Sopenharmony_ci    if (usec != (pa_usec_t) -1)
136253a5a1b3Sopenharmony_ci        usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
136353a5a1b3Sopenharmony_ci
136453a5a1b3Sopenharmony_ci    i->thread_info.requested_sink_latency = usec;
136553a5a1b3Sopenharmony_ci    pa_sink_invalidate_requested_latency(i->sink, true);
136653a5a1b3Sopenharmony_ci
136753a5a1b3Sopenharmony_ci    return usec;
136853a5a1b3Sopenharmony_ci}
136953a5a1b3Sopenharmony_ci
137053a5a1b3Sopenharmony_ci/* Called from main context */
137153a5a1b3Sopenharmony_cipa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
137253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
137353a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
137453a5a1b3Sopenharmony_ci
137553a5a1b3Sopenharmony_ci    if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
137653a5a1b3Sopenharmony_ci        pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
137753a5a1b3Sopenharmony_ci        return usec;
137853a5a1b3Sopenharmony_ci    }
137953a5a1b3Sopenharmony_ci
138053a5a1b3Sopenharmony_ci    /* If this sink input is not realized yet or we are being moved,
138153a5a1b3Sopenharmony_ci     * we have to touch the thread info data directly */
138253a5a1b3Sopenharmony_ci
138353a5a1b3Sopenharmony_ci    if (i->sink) {
138453a5a1b3Sopenharmony_ci        if (!(i->sink->flags & PA_SINK_DYNAMIC_LATENCY))
138553a5a1b3Sopenharmony_ci            usec = pa_sink_get_fixed_latency(i->sink);
138653a5a1b3Sopenharmony_ci
138753a5a1b3Sopenharmony_ci        if (usec != (pa_usec_t) -1) {
138853a5a1b3Sopenharmony_ci            pa_usec_t min_latency, max_latency;
138953a5a1b3Sopenharmony_ci            pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
139053a5a1b3Sopenharmony_ci            usec = PA_CLAMP(usec, min_latency, max_latency);
139153a5a1b3Sopenharmony_ci        }
139253a5a1b3Sopenharmony_ci    }
139353a5a1b3Sopenharmony_ci
139453a5a1b3Sopenharmony_ci    i->thread_info.requested_sink_latency = usec;
139553a5a1b3Sopenharmony_ci
139653a5a1b3Sopenharmony_ci    return usec;
139753a5a1b3Sopenharmony_ci}
139853a5a1b3Sopenharmony_ci
139953a5a1b3Sopenharmony_ci/* Called from main context */
140053a5a1b3Sopenharmony_cipa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
140153a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
140253a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
140353a5a1b3Sopenharmony_ci
140453a5a1b3Sopenharmony_ci    if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
140553a5a1b3Sopenharmony_ci        pa_usec_t usec = 0;
140653a5a1b3Sopenharmony_ci        pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
140753a5a1b3Sopenharmony_ci        return usec;
140853a5a1b3Sopenharmony_ci    }
140953a5a1b3Sopenharmony_ci
141053a5a1b3Sopenharmony_ci    /* If this sink input is not realized yet or we are being moved,
141153a5a1b3Sopenharmony_ci     * we have to touch the thread info data directly */
141253a5a1b3Sopenharmony_ci
141353a5a1b3Sopenharmony_ci    return i->thread_info.requested_sink_latency;
141453a5a1b3Sopenharmony_ci}
141553a5a1b3Sopenharmony_ci
141653a5a1b3Sopenharmony_ci/* Called from main context */
141753a5a1b3Sopenharmony_civoid pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, bool save, bool absolute) {
141853a5a1b3Sopenharmony_ci    pa_cvolume v;
141953a5a1b3Sopenharmony_ci
142053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
142153a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
142253a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
142353a5a1b3Sopenharmony_ci    pa_assert(volume);
142453a5a1b3Sopenharmony_ci    pa_assert(pa_cvolume_valid(volume));
142553a5a1b3Sopenharmony_ci    pa_assert(volume->channels == 1 || pa_cvolume_compatible(volume, &i->sample_spec));
142653a5a1b3Sopenharmony_ci    pa_assert(i->volume_writable);
142753a5a1b3Sopenharmony_ci
142853a5a1b3Sopenharmony_ci    if (!absolute && pa_sink_flat_volume_enabled(i->sink)) {
142953a5a1b3Sopenharmony_ci        v = i->sink->reference_volume;
143053a5a1b3Sopenharmony_ci        pa_cvolume_remap(&v, &i->sink->channel_map, &i->channel_map);
143153a5a1b3Sopenharmony_ci
143253a5a1b3Sopenharmony_ci        if (pa_cvolume_compatible(volume, &i->sample_spec))
143353a5a1b3Sopenharmony_ci            volume = pa_sw_cvolume_multiply(&v, &v, volume);
143453a5a1b3Sopenharmony_ci        else
143553a5a1b3Sopenharmony_ci            volume = pa_sw_cvolume_multiply_scalar(&v, &v, pa_cvolume_max(volume));
143653a5a1b3Sopenharmony_ci    } else {
143753a5a1b3Sopenharmony_ci        if (!pa_cvolume_compatible(volume, &i->sample_spec)) {
143853a5a1b3Sopenharmony_ci            v = i->volume;
143953a5a1b3Sopenharmony_ci            volume = pa_cvolume_scale(&v, pa_cvolume_max(volume));
144053a5a1b3Sopenharmony_ci        }
144153a5a1b3Sopenharmony_ci    }
144253a5a1b3Sopenharmony_ci
144353a5a1b3Sopenharmony_ci    if (pa_cvolume_equal(volume, &i->volume)) {
144453a5a1b3Sopenharmony_ci        i->save_volume = i->save_volume || save;
144553a5a1b3Sopenharmony_ci        return;
144653a5a1b3Sopenharmony_ci    }
144753a5a1b3Sopenharmony_ci
144853a5a1b3Sopenharmony_ci    pa_sink_input_set_volume_direct(i, volume);
144953a5a1b3Sopenharmony_ci    i->save_volume = save;
145053a5a1b3Sopenharmony_ci
145153a5a1b3Sopenharmony_ci    if (pa_sink_flat_volume_enabled(i->sink)) {
145253a5a1b3Sopenharmony_ci        /* We are in flat volume mode, so let's update all sink input
145353a5a1b3Sopenharmony_ci         * volumes and update the flat volume of the sink */
145453a5a1b3Sopenharmony_ci
145553a5a1b3Sopenharmony_ci        pa_sink_set_volume(i->sink, NULL, true, save);
145653a5a1b3Sopenharmony_ci
145753a5a1b3Sopenharmony_ci    } else {
145853a5a1b3Sopenharmony_ci        /* OK, we are in normal volume mode. The volume only affects
145953a5a1b3Sopenharmony_ci         * ourselves */
146053a5a1b3Sopenharmony_ci        set_real_ratio(i, volume);
146153a5a1b3Sopenharmony_ci        pa_sink_input_set_reference_ratio(i, &i->volume);
146253a5a1b3Sopenharmony_ci
146353a5a1b3Sopenharmony_ci        /* Copy the new soft_volume to the thread_info struct */
146453a5a1b3Sopenharmony_ci        pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
146553a5a1b3Sopenharmony_ci    }
146653a5a1b3Sopenharmony_ci}
146753a5a1b3Sopenharmony_ci
146853a5a1b3Sopenharmony_civoid pa_sink_input_add_volume_factor(pa_sink_input *i, const char *key, const pa_cvolume *volume_factor) {
146953a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
147053a5a1b3Sopenharmony_ci
147153a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
147253a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
147353a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
147453a5a1b3Sopenharmony_ci    pa_assert(volume_factor);
147553a5a1b3Sopenharmony_ci    pa_assert(key);
147653a5a1b3Sopenharmony_ci    pa_assert(pa_cvolume_valid(volume_factor));
147753a5a1b3Sopenharmony_ci    pa_assert(volume_factor->channels == 1 || pa_cvolume_compatible(volume_factor, &i->sample_spec));
147853a5a1b3Sopenharmony_ci
147953a5a1b3Sopenharmony_ci    v = volume_factor_entry_new(key, volume_factor);
148053a5a1b3Sopenharmony_ci    if (!pa_cvolume_compatible(volume_factor, &i->sample_spec))
148153a5a1b3Sopenharmony_ci        pa_cvolume_set(&v->volume, i->sample_spec.channels, volume_factor->values[0]);
148253a5a1b3Sopenharmony_ci
148353a5a1b3Sopenharmony_ci    pa_assert_se(pa_hashmap_put(i->volume_factor_items, v->key, v) >= 0);
148453a5a1b3Sopenharmony_ci    if (pa_hashmap_size(i->volume_factor_items) == 1)
148553a5a1b3Sopenharmony_ci        i->volume_factor = v->volume;
148653a5a1b3Sopenharmony_ci    else
148753a5a1b3Sopenharmony_ci        pa_sw_cvolume_multiply(&i->volume_factor, &i->volume_factor, &v->volume);
148853a5a1b3Sopenharmony_ci
148953a5a1b3Sopenharmony_ci    pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
149053a5a1b3Sopenharmony_ci
149153a5a1b3Sopenharmony_ci    /* Copy the new soft_volume to the thread_info struct */
149253a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
149353a5a1b3Sopenharmony_ci}
149453a5a1b3Sopenharmony_ci
149553a5a1b3Sopenharmony_ci/* Returns 0 if an entry was removed and -1 if no entry for the given key was
149653a5a1b3Sopenharmony_ci * found. */
149753a5a1b3Sopenharmony_ciint pa_sink_input_remove_volume_factor(pa_sink_input *i, const char *key) {
149853a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
149953a5a1b3Sopenharmony_ci
150053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
150153a5a1b3Sopenharmony_ci    pa_assert(key);
150253a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
150353a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
150453a5a1b3Sopenharmony_ci
150553a5a1b3Sopenharmony_ci    if (pa_hashmap_remove_and_free(i->volume_factor_items, key) < 0)
150653a5a1b3Sopenharmony_ci        return -1;
150753a5a1b3Sopenharmony_ci
150853a5a1b3Sopenharmony_ci    switch (pa_hashmap_size(i->volume_factor_items)) {
150953a5a1b3Sopenharmony_ci        case 0:
151053a5a1b3Sopenharmony_ci            pa_cvolume_reset(&i->volume_factor, i->sample_spec.channels);
151153a5a1b3Sopenharmony_ci            break;
151253a5a1b3Sopenharmony_ci        case 1:
151353a5a1b3Sopenharmony_ci            v = pa_hashmap_first(i->volume_factor_items);
151453a5a1b3Sopenharmony_ci            i->volume_factor = v->volume;
151553a5a1b3Sopenharmony_ci            break;
151653a5a1b3Sopenharmony_ci        default:
151753a5a1b3Sopenharmony_ci            volume_factor_from_hashmap(&i->volume_factor, i->volume_factor_items, i->volume_factor.channels);
151853a5a1b3Sopenharmony_ci    }
151953a5a1b3Sopenharmony_ci
152053a5a1b3Sopenharmony_ci    pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
152153a5a1b3Sopenharmony_ci
152253a5a1b3Sopenharmony_ci    /* Copy the new soft_volume to the thread_info struct */
152353a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME, NULL, 0, NULL) == 0);
152453a5a1b3Sopenharmony_ci
152553a5a1b3Sopenharmony_ci    return 0;
152653a5a1b3Sopenharmony_ci}
152753a5a1b3Sopenharmony_ci
152853a5a1b3Sopenharmony_ci/* Called from main context */
152953a5a1b3Sopenharmony_cistatic void set_real_ratio(pa_sink_input *i, const pa_cvolume *v) {
153053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
153153a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
153253a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
153353a5a1b3Sopenharmony_ci    pa_assert(!v || pa_cvolume_compatible(v, &i->sample_spec));
153453a5a1b3Sopenharmony_ci
153553a5a1b3Sopenharmony_ci    /* This basically calculates:
153653a5a1b3Sopenharmony_ci     *
153753a5a1b3Sopenharmony_ci     * i->real_ratio := v
153853a5a1b3Sopenharmony_ci     * i->soft_volume := i->real_ratio * i->volume_factor */
153953a5a1b3Sopenharmony_ci
154053a5a1b3Sopenharmony_ci    if (v)
154153a5a1b3Sopenharmony_ci        i->real_ratio = *v;
154253a5a1b3Sopenharmony_ci    else
154353a5a1b3Sopenharmony_ci        pa_cvolume_reset(&i->real_ratio, i->sample_spec.channels);
154453a5a1b3Sopenharmony_ci
154553a5a1b3Sopenharmony_ci    pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
154653a5a1b3Sopenharmony_ci    /* We don't copy the data to the thread_info data. That's left for someone else to do */
154753a5a1b3Sopenharmony_ci}
154853a5a1b3Sopenharmony_ci
154953a5a1b3Sopenharmony_ci/* Called from main or I/O context */
155053a5a1b3Sopenharmony_cibool pa_sink_input_is_passthrough(pa_sink_input *i) {
155153a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
155253a5a1b3Sopenharmony_ci
155353a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(!pa_format_info_is_pcm(i->format)))
155453a5a1b3Sopenharmony_ci        return true;
155553a5a1b3Sopenharmony_ci
155653a5a1b3Sopenharmony_ci    if (PA_UNLIKELY(i->flags & PA_SINK_INPUT_PASSTHROUGH))
155753a5a1b3Sopenharmony_ci        return true;
155853a5a1b3Sopenharmony_ci
155953a5a1b3Sopenharmony_ci    return false;
156053a5a1b3Sopenharmony_ci}
156153a5a1b3Sopenharmony_ci
156253a5a1b3Sopenharmony_ci/* Called from main context */
156353a5a1b3Sopenharmony_cibool pa_sink_input_is_volume_readable(pa_sink_input *i) {
156453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
156553a5a1b3Sopenharmony_ci    // pa_assert_ctl_context();
156653a5a1b3Sopenharmony_ci
156753a5a1b3Sopenharmony_ci    return !pa_sink_input_is_passthrough(i);
156853a5a1b3Sopenharmony_ci}
156953a5a1b3Sopenharmony_ci
157053a5a1b3Sopenharmony_ci/* Called from main context */
157153a5a1b3Sopenharmony_cipa_cvolume *pa_sink_input_get_volume(pa_sink_input *i, pa_cvolume *volume, bool absolute) {
157253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
157353a5a1b3Sopenharmony_ci    // pa_assert_ctl_context();
157453a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
157553a5a1b3Sopenharmony_ci    pa_assert(pa_sink_input_is_volume_readable(i));
157653a5a1b3Sopenharmony_ci
157753a5a1b3Sopenharmony_ci    if (absolute || !pa_sink_flat_volume_enabled(i->sink))
157853a5a1b3Sopenharmony_ci        *volume = i->volume;
157953a5a1b3Sopenharmony_ci    else
158053a5a1b3Sopenharmony_ci        *volume = i->reference_ratio;
158153a5a1b3Sopenharmony_ci
158253a5a1b3Sopenharmony_ci    return volume;
158353a5a1b3Sopenharmony_ci}
158453a5a1b3Sopenharmony_ci
158553a5a1b3Sopenharmony_ci/* Called from main context */
158653a5a1b3Sopenharmony_civoid pa_sink_input_set_mute(pa_sink_input *i, bool mute, bool save) {
158753a5a1b3Sopenharmony_ci    bool old_mute;
158853a5a1b3Sopenharmony_ci
158953a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
159053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
159153a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
159253a5a1b3Sopenharmony_ci
159353a5a1b3Sopenharmony_ci    old_mute = i->muted;
159453a5a1b3Sopenharmony_ci
159553a5a1b3Sopenharmony_ci    if (mute == old_mute) {
159653a5a1b3Sopenharmony_ci        i->save_muted |= save;
159753a5a1b3Sopenharmony_ci        return;
159853a5a1b3Sopenharmony_ci    }
159953a5a1b3Sopenharmony_ci
160053a5a1b3Sopenharmony_ci    i->muted = mute;
160153a5a1b3Sopenharmony_ci    pa_log_debug("The mute of sink input %u changed from %s to %s.", i->index, pa_yes_no(old_mute), pa_yes_no(mute));
160253a5a1b3Sopenharmony_ci
160353a5a1b3Sopenharmony_ci    i->save_muted = save;
160453a5a1b3Sopenharmony_ci
160553a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE, NULL, 0, NULL) == 0);
160653a5a1b3Sopenharmony_ci
160753a5a1b3Sopenharmony_ci    /* The mute status changed, let's tell people so */
160853a5a1b3Sopenharmony_ci    if (i->mute_changed)
160953a5a1b3Sopenharmony_ci        i->mute_changed(i);
161053a5a1b3Sopenharmony_ci
161153a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
161253a5a1b3Sopenharmony_ci    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MUTE_CHANGED], i);
161353a5a1b3Sopenharmony_ci}
161453a5a1b3Sopenharmony_ci
161553a5a1b3Sopenharmony_civoid pa_sink_input_set_property(pa_sink_input *i, const char *key, const char *value) {
161653a5a1b3Sopenharmony_ci    char *old_value = NULL;
161753a5a1b3Sopenharmony_ci    const char *new_value;
161853a5a1b3Sopenharmony_ci
161953a5a1b3Sopenharmony_ci    pa_assert(i);
162053a5a1b3Sopenharmony_ci    pa_assert(key);
162153a5a1b3Sopenharmony_ci
162253a5a1b3Sopenharmony_ci    if (pa_proplist_contains(i->proplist, key)) {
162353a5a1b3Sopenharmony_ci        old_value = pa_xstrdup(pa_proplist_gets(i->proplist, key));
162453a5a1b3Sopenharmony_ci        if (value && old_value && pa_streq(value, old_value))
162553a5a1b3Sopenharmony_ci            goto finish;
162653a5a1b3Sopenharmony_ci
162753a5a1b3Sopenharmony_ci        if (!old_value)
162853a5a1b3Sopenharmony_ci            old_value = pa_xstrdup("(data)");
162953a5a1b3Sopenharmony_ci    } else {
163053a5a1b3Sopenharmony_ci        if (!value)
163153a5a1b3Sopenharmony_ci            goto finish;
163253a5a1b3Sopenharmony_ci
163353a5a1b3Sopenharmony_ci        old_value = pa_xstrdup("(unset)");
163453a5a1b3Sopenharmony_ci    }
163553a5a1b3Sopenharmony_ci
163653a5a1b3Sopenharmony_ci    if (value) {
163753a5a1b3Sopenharmony_ci        pa_proplist_sets(i->proplist, key, value);
163853a5a1b3Sopenharmony_ci        new_value = value;
163953a5a1b3Sopenharmony_ci    } else {
164053a5a1b3Sopenharmony_ci        pa_proplist_unset(i->proplist, key);
164153a5a1b3Sopenharmony_ci        new_value = "(unset)";
164253a5a1b3Sopenharmony_ci    }
164353a5a1b3Sopenharmony_ci
164453a5a1b3Sopenharmony_ci    if (PA_SINK_INPUT_IS_LINKED(i->state)) {
164553a5a1b3Sopenharmony_ci        pa_log_debug("Sink input %u: proplist[%s]: %s -> %s", i->index, key, old_value, new_value);
164653a5a1b3Sopenharmony_ci        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
164753a5a1b3Sopenharmony_ci        pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
164853a5a1b3Sopenharmony_ci    }
164953a5a1b3Sopenharmony_ci
165053a5a1b3Sopenharmony_cifinish:
165153a5a1b3Sopenharmony_ci    pa_xfree(old_value);
165253a5a1b3Sopenharmony_ci}
165353a5a1b3Sopenharmony_ci
165453a5a1b3Sopenharmony_civoid pa_sink_input_set_property_arbitrary(pa_sink_input *i, const char *key, const uint8_t *value, size_t nbytes) {
165553a5a1b3Sopenharmony_ci    const uint8_t *old_value;
165653a5a1b3Sopenharmony_ci    size_t old_nbytes;
165753a5a1b3Sopenharmony_ci    const char *old_value_str;
165853a5a1b3Sopenharmony_ci    const char *new_value_str;
165953a5a1b3Sopenharmony_ci
166053a5a1b3Sopenharmony_ci    pa_assert(i);
166153a5a1b3Sopenharmony_ci    pa_assert(key);
166253a5a1b3Sopenharmony_ci
166353a5a1b3Sopenharmony_ci    if (pa_proplist_get(i->proplist, key, (const void **) &old_value, &old_nbytes) >= 0) {
166453a5a1b3Sopenharmony_ci        if (value && nbytes == old_nbytes && !memcmp(value, old_value, nbytes))
166553a5a1b3Sopenharmony_ci            return;
166653a5a1b3Sopenharmony_ci
166753a5a1b3Sopenharmony_ci        old_value_str = "(data)";
166853a5a1b3Sopenharmony_ci
166953a5a1b3Sopenharmony_ci    } else {
167053a5a1b3Sopenharmony_ci        if (!value)
167153a5a1b3Sopenharmony_ci            return;
167253a5a1b3Sopenharmony_ci
167353a5a1b3Sopenharmony_ci        old_value_str = "(unset)";
167453a5a1b3Sopenharmony_ci    }
167553a5a1b3Sopenharmony_ci
167653a5a1b3Sopenharmony_ci    if (value) {
167753a5a1b3Sopenharmony_ci        pa_proplist_set(i->proplist, key, value, nbytes);
167853a5a1b3Sopenharmony_ci        new_value_str = "(data)";
167953a5a1b3Sopenharmony_ci    } else {
168053a5a1b3Sopenharmony_ci        pa_proplist_unset(i->proplist, key);
168153a5a1b3Sopenharmony_ci        new_value_str = "(unset)";
168253a5a1b3Sopenharmony_ci    }
168353a5a1b3Sopenharmony_ci
168453a5a1b3Sopenharmony_ci    if (PA_SINK_INPUT_IS_LINKED(i->state)) {
168553a5a1b3Sopenharmony_ci        pa_log_debug("Sink input %u: proplist[%s]: %s -> %s", i->index, key, old_value_str, new_value_str);
168653a5a1b3Sopenharmony_ci        pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
168753a5a1b3Sopenharmony_ci        pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
168853a5a1b3Sopenharmony_ci    }
168953a5a1b3Sopenharmony_ci}
169053a5a1b3Sopenharmony_ci
169153a5a1b3Sopenharmony_ci/* Called from main thread */
169253a5a1b3Sopenharmony_civoid pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
169353a5a1b3Sopenharmony_ci    void *state;
169453a5a1b3Sopenharmony_ci    const char *key;
169553a5a1b3Sopenharmony_ci    const uint8_t *value;
169653a5a1b3Sopenharmony_ci    size_t nbytes;
169753a5a1b3Sopenharmony_ci
169853a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
169953a5a1b3Sopenharmony_ci    pa_assert(p);
170053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
170153a5a1b3Sopenharmony_ci
170253a5a1b3Sopenharmony_ci    switch (mode) {
170353a5a1b3Sopenharmony_ci        case PA_UPDATE_SET:
170453a5a1b3Sopenharmony_ci            /* Delete everything that is not in p. */
170553a5a1b3Sopenharmony_ci            for (state = NULL; (key = pa_proplist_iterate(i->proplist, &state));) {
170653a5a1b3Sopenharmony_ci                if (!pa_proplist_contains(p, key))
170753a5a1b3Sopenharmony_ci                    pa_sink_input_set_property(i, key, NULL);
170853a5a1b3Sopenharmony_ci            }
170953a5a1b3Sopenharmony_ci
171053a5a1b3Sopenharmony_ci            /* Fall through. */
171153a5a1b3Sopenharmony_ci        case PA_UPDATE_REPLACE:
171253a5a1b3Sopenharmony_ci            for (state = NULL; (key = pa_proplist_iterate(p, &state));) {
171353a5a1b3Sopenharmony_ci                pa_proplist_get(p, key, (const void **) &value, &nbytes);
171453a5a1b3Sopenharmony_ci                pa_sink_input_set_property_arbitrary(i, key, value, nbytes);
171553a5a1b3Sopenharmony_ci            }
171653a5a1b3Sopenharmony_ci
171753a5a1b3Sopenharmony_ci            break;
171853a5a1b3Sopenharmony_ci        case PA_UPDATE_MERGE:
171953a5a1b3Sopenharmony_ci            for (state = NULL; (key = pa_proplist_iterate(p, &state));) {
172053a5a1b3Sopenharmony_ci                if (pa_proplist_contains(i->proplist, key))
172153a5a1b3Sopenharmony_ci                    continue;
172253a5a1b3Sopenharmony_ci
172353a5a1b3Sopenharmony_ci                pa_proplist_get(p, key, (const void **) &value, &nbytes);
172453a5a1b3Sopenharmony_ci                pa_sink_input_set_property_arbitrary(i, key, value, nbytes);
172553a5a1b3Sopenharmony_ci            }
172653a5a1b3Sopenharmony_ci
172753a5a1b3Sopenharmony_ci            break;
172853a5a1b3Sopenharmony_ci    }
172953a5a1b3Sopenharmony_ci}
173053a5a1b3Sopenharmony_ci
173153a5a1b3Sopenharmony_ci/* Called from main context */
173253a5a1b3Sopenharmony_civoid pa_sink_input_cork(pa_sink_input *i, bool b) {
173353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
173453a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
173553a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
173653a5a1b3Sopenharmony_ci
173753a5a1b3Sopenharmony_ci    sink_input_set_state(i, b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING);
173853a5a1b3Sopenharmony_ci
173953a5a1b3Sopenharmony_ci    if (b && i->thread_info.resampler) {
174053a5a1b3Sopenharmony_ci        pa_resampler_reset(i->thread_info.resampler);
174153a5a1b3Sopenharmony_ci    }
174253a5a1b3Sopenharmony_ci}
174353a5a1b3Sopenharmony_ci
174453a5a1b3Sopenharmony_ci/* Called from main context */
174553a5a1b3Sopenharmony_ciint pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) {
174653a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
174753a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
174853a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
174953a5a1b3Sopenharmony_ci    pa_return_val_if_fail(i->thread_info.resampler, -PA_ERR_BADSTATE);
175053a5a1b3Sopenharmony_ci
175153a5a1b3Sopenharmony_ci    if (i->sample_spec.rate == rate)
175253a5a1b3Sopenharmony_ci        return 0;
175353a5a1b3Sopenharmony_ci
175453a5a1b3Sopenharmony_ci    i->sample_spec.rate = rate;
175553a5a1b3Sopenharmony_ci
175653a5a1b3Sopenharmony_ci    if (i->sink)
175753a5a1b3Sopenharmony_ci        pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_RATE, PA_UINT_TO_PTR(rate), 0, NULL, NULL);
175853a5a1b3Sopenharmony_ci    else {
175953a5a1b3Sopenharmony_ci        i->thread_info.sample_spec.rate = rate;
176053a5a1b3Sopenharmony_ci        pa_resampler_set_input_rate(i->thread_info.resampler, rate);
176153a5a1b3Sopenharmony_ci    }
176253a5a1b3Sopenharmony_ci
176353a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
176453a5a1b3Sopenharmony_ci    return 0;
176553a5a1b3Sopenharmony_ci}
176653a5a1b3Sopenharmony_ci
176753a5a1b3Sopenharmony_ci/* Called from main context */
176853a5a1b3Sopenharmony_cipa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
176953a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
177053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
177153a5a1b3Sopenharmony_ci
177253a5a1b3Sopenharmony_ci    return i->actual_resample_method;
177353a5a1b3Sopenharmony_ci}
177453a5a1b3Sopenharmony_ci
177553a5a1b3Sopenharmony_ci/* Called from main context */
177653a5a1b3Sopenharmony_cibool pa_sink_input_may_move(pa_sink_input *i) {
177753a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
177853a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
177953a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
178053a5a1b3Sopenharmony_ci
178153a5a1b3Sopenharmony_ci    if (i->flags & PA_SINK_INPUT_DONT_MOVE)
178253a5a1b3Sopenharmony_ci        return false;
178353a5a1b3Sopenharmony_ci
178453a5a1b3Sopenharmony_ci    if (i->sync_next || i->sync_prev) {
178553a5a1b3Sopenharmony_ci        pa_log_warn("Moving synchronized streams not supported.");
178653a5a1b3Sopenharmony_ci        return false;
178753a5a1b3Sopenharmony_ci    }
178853a5a1b3Sopenharmony_ci
178953a5a1b3Sopenharmony_ci    return true;
179053a5a1b3Sopenharmony_ci}
179153a5a1b3Sopenharmony_ci
179253a5a1b3Sopenharmony_cistatic bool find_filter_sink_input(pa_sink_input *target, pa_sink *s) {
179353a5a1b3Sopenharmony_ci    unsigned PA_UNUSED i = 0;
179453a5a1b3Sopenharmony_ci    while (s && s->input_to_master) {
179553a5a1b3Sopenharmony_ci        if (s->input_to_master == target)
179653a5a1b3Sopenharmony_ci            return true;
179753a5a1b3Sopenharmony_ci        s = s->input_to_master->sink;
179853a5a1b3Sopenharmony_ci        pa_assert(i++ < 100);
179953a5a1b3Sopenharmony_ci    }
180053a5a1b3Sopenharmony_ci    return false;
180153a5a1b3Sopenharmony_ci}
180253a5a1b3Sopenharmony_ci
180353a5a1b3Sopenharmony_cistatic bool is_filter_sink_moving(pa_sink_input *i) {
180453a5a1b3Sopenharmony_ci    pa_sink *sink = i->sink;
180553a5a1b3Sopenharmony_ci
180653a5a1b3Sopenharmony_ci    if (!sink)
180753a5a1b3Sopenharmony_ci        return false;
180853a5a1b3Sopenharmony_ci
180953a5a1b3Sopenharmony_ci    while (sink->input_to_master) {
181053a5a1b3Sopenharmony_ci        sink = sink->input_to_master->sink;
181153a5a1b3Sopenharmony_ci
181253a5a1b3Sopenharmony_ci        if (!sink)
181353a5a1b3Sopenharmony_ci            return true;
181453a5a1b3Sopenharmony_ci    }
181553a5a1b3Sopenharmony_ci
181653a5a1b3Sopenharmony_ci    return false;
181753a5a1b3Sopenharmony_ci}
181853a5a1b3Sopenharmony_ci
181953a5a1b3Sopenharmony_ci/* Called from main context */
182053a5a1b3Sopenharmony_cibool pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
182153a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
182253a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
182353a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
182453a5a1b3Sopenharmony_ci    pa_sink_assert_ref(dest);
182553a5a1b3Sopenharmony_ci
182653a5a1b3Sopenharmony_ci    if (dest == i->sink)
182753a5a1b3Sopenharmony_ci        return true;
182853a5a1b3Sopenharmony_ci
182953a5a1b3Sopenharmony_ci    if (dest->unlink_requested)
183053a5a1b3Sopenharmony_ci        return false;
183153a5a1b3Sopenharmony_ci
183253a5a1b3Sopenharmony_ci    if (!pa_sink_input_may_move(i))
183353a5a1b3Sopenharmony_ci        return false;
183453a5a1b3Sopenharmony_ci
183553a5a1b3Sopenharmony_ci    /* Make sure we're not creating a filter sink cycle */
183653a5a1b3Sopenharmony_ci    if (find_filter_sink_input(i, dest)) {
183753a5a1b3Sopenharmony_ci        pa_log_debug("Can't connect input to %s, as that would create a cycle.", dest->name);
183853a5a1b3Sopenharmony_ci        return false;
183953a5a1b3Sopenharmony_ci    }
184053a5a1b3Sopenharmony_ci
184153a5a1b3Sopenharmony_ci    /* If this sink input is connected to a filter sink that itself is moving,
184253a5a1b3Sopenharmony_ci     * then don't allow the move. Moving requires sending a message to the IO
184353a5a1b3Sopenharmony_ci     * thread of the old sink, and if the old sink is a filter sink that is
184453a5a1b3Sopenharmony_ci     * moving, there's no IO thread associated to the old sink. */
184553a5a1b3Sopenharmony_ci    if (is_filter_sink_moving(i)) {
184653a5a1b3Sopenharmony_ci        pa_log_debug("Can't move input from filter sink %s, because the filter sink itself is currently moving.",
184753a5a1b3Sopenharmony_ci                     i->sink->name);
184853a5a1b3Sopenharmony_ci        return false;
184953a5a1b3Sopenharmony_ci    }
185053a5a1b3Sopenharmony_ci
185153a5a1b3Sopenharmony_ci    if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
185253a5a1b3Sopenharmony_ci        pa_log_warn("Failed to move sink input: too many inputs per sink.");
185353a5a1b3Sopenharmony_ci        return false;
185453a5a1b3Sopenharmony_ci    }
185553a5a1b3Sopenharmony_ci
185653a5a1b3Sopenharmony_ci    if (check_passthrough_connection(pa_sink_input_is_passthrough(i), dest) < 0)
185753a5a1b3Sopenharmony_ci        return false;
185853a5a1b3Sopenharmony_ci
185953a5a1b3Sopenharmony_ci    if (i->may_move_to)
186053a5a1b3Sopenharmony_ci        if (!i->may_move_to(i, dest))
186153a5a1b3Sopenharmony_ci            return false;
186253a5a1b3Sopenharmony_ci
186353a5a1b3Sopenharmony_ci    return true;
186453a5a1b3Sopenharmony_ci}
186553a5a1b3Sopenharmony_ci
186653a5a1b3Sopenharmony_ci/* Called from main context */
186753a5a1b3Sopenharmony_ciint pa_sink_input_start_move(pa_sink_input *i) {
186853a5a1b3Sopenharmony_ci    pa_source_output *o, PA_UNUSED *p = NULL;
186953a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
187053a5a1b3Sopenharmony_ci    void *state = NULL;
187153a5a1b3Sopenharmony_ci    int r;
187253a5a1b3Sopenharmony_ci
187353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
187453a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
187553a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
187653a5a1b3Sopenharmony_ci    pa_assert(i->sink);
187753a5a1b3Sopenharmony_ci
187853a5a1b3Sopenharmony_ci    if (!pa_sink_input_may_move(i))
187953a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
188053a5a1b3Sopenharmony_ci
188153a5a1b3Sopenharmony_ci    if ((r = pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_START], i)) < 0)
188253a5a1b3Sopenharmony_ci        return r;
188353a5a1b3Sopenharmony_ci
188453a5a1b3Sopenharmony_ci    pa_log_debug("Starting to move sink input %u from '%s'", (unsigned) i->index, i->sink->name);
188553a5a1b3Sopenharmony_ci
188653a5a1b3Sopenharmony_ci    /* Kill directly connected outputs */
188753a5a1b3Sopenharmony_ci    while ((o = pa_idxset_first(i->direct_outputs, NULL))) {
188853a5a1b3Sopenharmony_ci        pa_assert(o != p);
188953a5a1b3Sopenharmony_ci        pa_source_output_kill(o);
189053a5a1b3Sopenharmony_ci        p = o;
189153a5a1b3Sopenharmony_ci    }
189253a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(i->direct_outputs));
189353a5a1b3Sopenharmony_ci
189453a5a1b3Sopenharmony_ci    pa_idxset_remove_by_data(i->sink->inputs, i, NULL);
189553a5a1b3Sopenharmony_ci
189653a5a1b3Sopenharmony_ci    if (i->state == PA_SINK_INPUT_CORKED)
189753a5a1b3Sopenharmony_ci        pa_assert_se(i->sink->n_corked-- >= 1);
189853a5a1b3Sopenharmony_ci
189953a5a1b3Sopenharmony_ci    if (pa_sink_input_is_passthrough(i))
190053a5a1b3Sopenharmony_ci        pa_sink_leave_passthrough(i->sink);
190153a5a1b3Sopenharmony_ci
190253a5a1b3Sopenharmony_ci    if (pa_sink_flat_volume_enabled(i->sink))
190353a5a1b3Sopenharmony_ci        /* We might need to update the sink's volume if we are in flat
190453a5a1b3Sopenharmony_ci         * volume mode. */
190553a5a1b3Sopenharmony_ci        pa_sink_set_volume(i->sink, NULL, false, false);
190653a5a1b3Sopenharmony_ci
190753a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
190853a5a1b3Sopenharmony_ci
190953a5a1b3Sopenharmony_ci    pa_sink_update_status(i->sink);
191053a5a1b3Sopenharmony_ci
191153a5a1b3Sopenharmony_ci    PA_HASHMAP_FOREACH(v, i->volume_factor_sink_items, state)
191253a5a1b3Sopenharmony_ci        pa_cvolume_remap(&v->volume, &i->sink->channel_map, &i->channel_map);
191353a5a1b3Sopenharmony_ci
191453a5a1b3Sopenharmony_ci    pa_cvolume_remap(&i->volume_factor_sink, &i->sink->channel_map, &i->channel_map);
191553a5a1b3Sopenharmony_ci
191653a5a1b3Sopenharmony_ci    /* Calculate how much of the latency was rewound on the old sink */
191753a5a1b3Sopenharmony_ci    i->origin_rewind_bytes = pa_sink_get_last_rewind(i->sink) / pa_frame_size(&i->sink->sample_spec);
191853a5a1b3Sopenharmony_ci    i->origin_rewind_bytes = i->origin_rewind_bytes * i->sample_spec.rate / i->sink->sample_spec.rate;
191953a5a1b3Sopenharmony_ci    i->origin_rewind_bytes *= pa_frame_size(&i->sample_spec);
192053a5a1b3Sopenharmony_ci
192153a5a1b3Sopenharmony_ci    i->sink = NULL;
192253a5a1b3Sopenharmony_ci    i->sink_requested_by_application = false;
192353a5a1b3Sopenharmony_ci
192453a5a1b3Sopenharmony_ci    pa_sink_input_unref(i);
192553a5a1b3Sopenharmony_ci
192653a5a1b3Sopenharmony_ci    return 0;
192753a5a1b3Sopenharmony_ci}
192853a5a1b3Sopenharmony_ci
192953a5a1b3Sopenharmony_ci/* Called from main context. If i has an origin sink that uses volume sharing,
193053a5a1b3Sopenharmony_ci * then also the origin sink and all streams connected to it need to update
193153a5a1b3Sopenharmony_ci * their volume - this function does all that by using recursion. */
193253a5a1b3Sopenharmony_cistatic void update_volume_due_to_moving(pa_sink_input *i, pa_sink *dest) {
193353a5a1b3Sopenharmony_ci    pa_cvolume new_volume;
193453a5a1b3Sopenharmony_ci
193553a5a1b3Sopenharmony_ci    pa_assert(i);
193653a5a1b3Sopenharmony_ci    pa_assert(dest);
193753a5a1b3Sopenharmony_ci    pa_assert(i->sink); /* The destination sink should already be set. */
193853a5a1b3Sopenharmony_ci
193953a5a1b3Sopenharmony_ci    if (i->origin_sink && (i->origin_sink->flags & PA_SINK_SHARE_VOLUME_WITH_MASTER)) {
194053a5a1b3Sopenharmony_ci        pa_sink *root_sink = pa_sink_get_master(i->sink);
194153a5a1b3Sopenharmony_ci        pa_sink_input *origin_sink_input;
194253a5a1b3Sopenharmony_ci        uint32_t idx;
194353a5a1b3Sopenharmony_ci
194453a5a1b3Sopenharmony_ci        if (PA_UNLIKELY(!root_sink))
194553a5a1b3Sopenharmony_ci            return;
194653a5a1b3Sopenharmony_ci
194753a5a1b3Sopenharmony_ci        if (pa_sink_flat_volume_enabled(i->sink)) {
194853a5a1b3Sopenharmony_ci            /* Ok, so the origin sink uses volume sharing, and flat volume is
194953a5a1b3Sopenharmony_ci             * enabled. The volume will have to be updated as follows:
195053a5a1b3Sopenharmony_ci             *
195153a5a1b3Sopenharmony_ci             *     i->volume := i->sink->real_volume
195253a5a1b3Sopenharmony_ci             *         (handled later by pa_sink_set_volume)
195353a5a1b3Sopenharmony_ci             *     i->reference_ratio := i->volume / i->sink->reference_volume
195453a5a1b3Sopenharmony_ci             *         (handled later by pa_sink_set_volume)
195553a5a1b3Sopenharmony_ci             *     i->real_ratio stays unchanged
195653a5a1b3Sopenharmony_ci             *         (streams whose origin sink uses volume sharing should
195753a5a1b3Sopenharmony_ci             *          always have real_ratio of 0 dB)
195853a5a1b3Sopenharmony_ci             *     i->soft_volume stays unchanged
195953a5a1b3Sopenharmony_ci             *         (streams whose origin sink uses volume sharing should
196053a5a1b3Sopenharmony_ci             *          always have volume_factor as soft_volume, so no change
196153a5a1b3Sopenharmony_ci             *          should be needed) */
196253a5a1b3Sopenharmony_ci
196353a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_is_norm(&i->real_ratio));
196453a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
196553a5a1b3Sopenharmony_ci
196653a5a1b3Sopenharmony_ci            /* Notifications will be sent by pa_sink_set_volume(). */
196753a5a1b3Sopenharmony_ci
196853a5a1b3Sopenharmony_ci        } else {
196953a5a1b3Sopenharmony_ci            /* Ok, so the origin sink uses volume sharing, and flat volume is
197053a5a1b3Sopenharmony_ci             * disabled. The volume will have to be updated as follows:
197153a5a1b3Sopenharmony_ci             *
197253a5a1b3Sopenharmony_ci             *     i->volume := 0 dB
197353a5a1b3Sopenharmony_ci             *     i->reference_ratio := 0 dB
197453a5a1b3Sopenharmony_ci             *     i->real_ratio stays unchanged
197553a5a1b3Sopenharmony_ci             *         (streams whose origin sink uses volume sharing should
197653a5a1b3Sopenharmony_ci             *          always have real_ratio of 0 dB)
197753a5a1b3Sopenharmony_ci             *     i->soft_volume stays unchanged
197853a5a1b3Sopenharmony_ci             *         (streams whose origin sink uses volume sharing should
197953a5a1b3Sopenharmony_ci             *          always have volume_factor as soft_volume, so no change
198053a5a1b3Sopenharmony_ci             *          should be needed) */
198153a5a1b3Sopenharmony_ci
198253a5a1b3Sopenharmony_ci            pa_cvolume_reset(&new_volume, i->volume.channels);
198353a5a1b3Sopenharmony_ci            pa_sink_input_set_volume_direct(i, &new_volume);
198453a5a1b3Sopenharmony_ci            pa_sink_input_set_reference_ratio(i, &new_volume);
198553a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_is_norm(&i->real_ratio));
198653a5a1b3Sopenharmony_ci            pa_assert(pa_cvolume_equal(&i->soft_volume, &i->volume_factor));
198753a5a1b3Sopenharmony_ci        }
198853a5a1b3Sopenharmony_ci
198953a5a1b3Sopenharmony_ci        /* Additionally, the origin sink volume needs updating:
199053a5a1b3Sopenharmony_ci         *
199153a5a1b3Sopenharmony_ci         *     i->origin_sink->reference_volume := root_sink->reference_volume
199253a5a1b3Sopenharmony_ci         *     i->origin_sink->real_volume := root_sink->real_volume
199353a5a1b3Sopenharmony_ci         *     i->origin_sink->soft_volume stays unchanged
199453a5a1b3Sopenharmony_ci         *         (sinks that use volume sharing should always have
199553a5a1b3Sopenharmony_ci         *          soft_volume of 0 dB) */
199653a5a1b3Sopenharmony_ci
199753a5a1b3Sopenharmony_ci        new_volume = root_sink->reference_volume;
199853a5a1b3Sopenharmony_ci        pa_cvolume_remap(&new_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
199953a5a1b3Sopenharmony_ci        pa_sink_set_reference_volume_direct(i->origin_sink, &new_volume);
200053a5a1b3Sopenharmony_ci
200153a5a1b3Sopenharmony_ci        i->origin_sink->real_volume = root_sink->real_volume;
200253a5a1b3Sopenharmony_ci        pa_cvolume_remap(&i->origin_sink->real_volume, &root_sink->channel_map, &i->origin_sink->channel_map);
200353a5a1b3Sopenharmony_ci
200453a5a1b3Sopenharmony_ci        pa_assert(pa_cvolume_is_norm(&i->origin_sink->soft_volume));
200553a5a1b3Sopenharmony_ci
200653a5a1b3Sopenharmony_ci        /* If you wonder whether i->origin_sink->set_volume() should be called
200753a5a1b3Sopenharmony_ci         * somewhere, that's not the case, because sinks that use volume
200853a5a1b3Sopenharmony_ci         * sharing shouldn't have any internal volume that set_volume() would
200953a5a1b3Sopenharmony_ci         * update. If you wonder whether the thread_info variables should be
201053a5a1b3Sopenharmony_ci         * synced, yes, they should, and it's done by the
201153a5a1b3Sopenharmony_ci         * PA_SINK_MESSAGE_FINISH_MOVE message handler. */
201253a5a1b3Sopenharmony_ci
201353a5a1b3Sopenharmony_ci        /* Recursively update origin sink inputs. */
201453a5a1b3Sopenharmony_ci        PA_IDXSET_FOREACH(origin_sink_input, i->origin_sink->inputs, idx)
201553a5a1b3Sopenharmony_ci            update_volume_due_to_moving(origin_sink_input, dest);
201653a5a1b3Sopenharmony_ci
201753a5a1b3Sopenharmony_ci    } else {
201853a5a1b3Sopenharmony_ci        if (pa_sink_flat_volume_enabled(i->sink)) {
201953a5a1b3Sopenharmony_ci            /* Ok, so this is a regular stream, and flat volume is enabled. The
202053a5a1b3Sopenharmony_ci             * volume will have to be updated as follows:
202153a5a1b3Sopenharmony_ci             *
202253a5a1b3Sopenharmony_ci             *     i->volume := i->reference_ratio * i->sink->reference_volume
202353a5a1b3Sopenharmony_ci             *     i->reference_ratio stays unchanged
202453a5a1b3Sopenharmony_ci             *     i->real_ratio := i->volume / i->sink->real_volume
202553a5a1b3Sopenharmony_ci             *         (handled later by pa_sink_set_volume)
202653a5a1b3Sopenharmony_ci             *     i->soft_volume := i->real_ratio * i->volume_factor
202753a5a1b3Sopenharmony_ci             *         (handled later by pa_sink_set_volume) */
202853a5a1b3Sopenharmony_ci
202953a5a1b3Sopenharmony_ci            new_volume = i->sink->reference_volume;
203053a5a1b3Sopenharmony_ci            pa_cvolume_remap(&new_volume, &i->sink->channel_map, &i->channel_map);
203153a5a1b3Sopenharmony_ci            pa_sw_cvolume_multiply(&new_volume, &new_volume, &i->reference_ratio);
203253a5a1b3Sopenharmony_ci            pa_sink_input_set_volume_direct(i, &new_volume);
203353a5a1b3Sopenharmony_ci
203453a5a1b3Sopenharmony_ci        } else {
203553a5a1b3Sopenharmony_ci            /* Ok, so this is a regular stream, and flat volume is disabled.
203653a5a1b3Sopenharmony_ci             * The volume will have to be updated as follows:
203753a5a1b3Sopenharmony_ci             *
203853a5a1b3Sopenharmony_ci             *     i->volume := i->reference_ratio
203953a5a1b3Sopenharmony_ci             *     i->reference_ratio stays unchanged
204053a5a1b3Sopenharmony_ci             *     i->real_ratio := i->reference_ratio
204153a5a1b3Sopenharmony_ci             *     i->soft_volume := i->real_ratio * i->volume_factor */
204253a5a1b3Sopenharmony_ci
204353a5a1b3Sopenharmony_ci            pa_sink_input_set_volume_direct(i, &i->reference_ratio);
204453a5a1b3Sopenharmony_ci            i->real_ratio = i->reference_ratio;
204553a5a1b3Sopenharmony_ci            pa_sw_cvolume_multiply(&i->soft_volume, &i->real_ratio, &i->volume_factor);
204653a5a1b3Sopenharmony_ci        }
204753a5a1b3Sopenharmony_ci    }
204853a5a1b3Sopenharmony_ci
204953a5a1b3Sopenharmony_ci    /* If i->sink == dest, then recursion has finished, and we can finally call
205053a5a1b3Sopenharmony_ci     * pa_sink_set_volume(), which will do the rest of the updates. */
205153a5a1b3Sopenharmony_ci    if ((i->sink == dest) && pa_sink_flat_volume_enabled(i->sink))
205253a5a1b3Sopenharmony_ci        pa_sink_set_volume(i->sink, NULL, false, i->save_volume);
205353a5a1b3Sopenharmony_ci}
205453a5a1b3Sopenharmony_ci
205553a5a1b3Sopenharmony_ci/* Called from the main thread. */
205653a5a1b3Sopenharmony_cistatic void set_preferred_sink(pa_sink_input *i, const char *sink_name) {
205753a5a1b3Sopenharmony_ci    pa_assert(i);
205853a5a1b3Sopenharmony_ci
205953a5a1b3Sopenharmony_ci    if (pa_safe_streq(i->preferred_sink, sink_name))
206053a5a1b3Sopenharmony_ci        return;
206153a5a1b3Sopenharmony_ci
206253a5a1b3Sopenharmony_ci    pa_log_debug("Sink input %u: preferred_sink: %s -> %s",
206353a5a1b3Sopenharmony_ci                 i->index, i->preferred_sink ? i->preferred_sink : "(unset)", sink_name ? sink_name : "(unset)");
206453a5a1b3Sopenharmony_ci    pa_xfree(i->preferred_sink);
206553a5a1b3Sopenharmony_ci    i->preferred_sink = pa_xstrdup(sink_name);
206653a5a1b3Sopenharmony_ci
206753a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
206853a5a1b3Sopenharmony_ci    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PREFERRED_SINK_CHANGED], i);
206953a5a1b3Sopenharmony_ci}
207053a5a1b3Sopenharmony_ci
207153a5a1b3Sopenharmony_ci/* Restores the render memblockq from the history memblockq during a move.
207253a5a1b3Sopenharmony_ci * Called from main context while the sink input is detached. */
207353a5a1b3Sopenharmony_cistatic void restore_render_memblockq(pa_sink_input *i) {
207453a5a1b3Sopenharmony_ci    size_t block_size, to_push;
207553a5a1b3Sopenharmony_ci    size_t latency_bytes = 0;
207653a5a1b3Sopenharmony_ci    size_t bytes_on_origin_sink = 0;
207753a5a1b3Sopenharmony_ci    size_t resampler_delay_bytes = 0;
207853a5a1b3Sopenharmony_ci
207953a5a1b3Sopenharmony_ci    /* Calculate how much of the latency was left on the old sink */
208053a5a1b3Sopenharmony_ci    latency_bytes = pa_usec_to_bytes(i->thread_info.origin_sink_latency, &i->sample_spec);
208153a5a1b3Sopenharmony_ci    if (latency_bytes > i->origin_rewind_bytes)
208253a5a1b3Sopenharmony_ci            bytes_on_origin_sink = latency_bytes - i->origin_rewind_bytes;
208353a5a1b3Sopenharmony_ci
208453a5a1b3Sopenharmony_ci    /* Get resampler latency of old resampler */
208553a5a1b3Sopenharmony_ci    resampler_delay_bytes = i->thread_info.resampler_delay_frames * pa_frame_size(&i->sample_spec);
208653a5a1b3Sopenharmony_ci
208753a5a1b3Sopenharmony_ci    /* Flush the render memblockq  and reset the resampler */
208853a5a1b3Sopenharmony_ci    pa_memblockq_flush_write(i->thread_info.render_memblockq, true);
208953a5a1b3Sopenharmony_ci    if (i->thread_info.resampler)
209053a5a1b3Sopenharmony_ci        pa_resampler_reset(i->thread_info.resampler);
209153a5a1b3Sopenharmony_ci
209253a5a1b3Sopenharmony_ci    /* Rewind the history queue */
209353a5a1b3Sopenharmony_ci    if (i->origin_rewind_bytes + resampler_delay_bytes > 0)
209453a5a1b3Sopenharmony_ci        pa_memblockq_rewind(i->thread_info.history_memblockq, i->origin_rewind_bytes + resampler_delay_bytes);
209553a5a1b3Sopenharmony_ci
209653a5a1b3Sopenharmony_ci    /* If something is left playing on the origin sink, add silence to the render memblockq */
209753a5a1b3Sopenharmony_ci    if (bytes_on_origin_sink > 0) {
209853a5a1b3Sopenharmony_ci        pa_memchunk chunk;;
209953a5a1b3Sopenharmony_ci
210053a5a1b3Sopenharmony_ci        chunk.length = pa_resampler_result(i->thread_info.resampler, bytes_on_origin_sink);
210153a5a1b3Sopenharmony_ci        if (chunk.length > 0) {
210253a5a1b3Sopenharmony_ci            chunk.memblock = pa_memblock_new(i->core->mempool, chunk.length);
210353a5a1b3Sopenharmony_ci            chunk.index = 0;
210453a5a1b3Sopenharmony_ci            pa_silence_memchunk(&chunk, &i->sink->sample_spec);
210553a5a1b3Sopenharmony_ci            pa_memblockq_push(i->thread_info.render_memblockq, &chunk);
210653a5a1b3Sopenharmony_ci            pa_memblock_unref(chunk.memblock);
210753a5a1b3Sopenharmony_ci        }
210853a5a1b3Sopenharmony_ci    }
210953a5a1b3Sopenharmony_ci
211053a5a1b3Sopenharmony_ci    /* Determine maximum block size */
211153a5a1b3Sopenharmony_ci    if (i->thread_info.resampler)
211253a5a1b3Sopenharmony_ci        block_size = pa_resampler_max_block_size(i->thread_info.resampler);
211353a5a1b3Sopenharmony_ci    else
211453a5a1b3Sopenharmony_ci        block_size = pa_frame_align(pa_mempool_block_size_max(i->core->mempool), &i->sample_spec);
211553a5a1b3Sopenharmony_ci
211653a5a1b3Sopenharmony_ci    /* Now push all the data in the history queue into the render memblockq */
211753a5a1b3Sopenharmony_ci    to_push = pa_memblockq_get_length(i->thread_info.history_memblockq);
211853a5a1b3Sopenharmony_ci    while (to_push > 0) {
211953a5a1b3Sopenharmony_ci        pa_memchunk in_chunk, out_chunk;
212053a5a1b3Sopenharmony_ci        size_t push_bytes;
212153a5a1b3Sopenharmony_ci
212253a5a1b3Sopenharmony_ci        push_bytes = block_size;
212353a5a1b3Sopenharmony_ci        if (to_push < block_size)
212453a5a1b3Sopenharmony_ci            push_bytes = to_push;
212553a5a1b3Sopenharmony_ci
212653a5a1b3Sopenharmony_ci        if (pa_memblockq_peek_fixed_size(i->thread_info.history_memblockq, push_bytes, &in_chunk) < 0) {
212753a5a1b3Sopenharmony_ci            pa_log_warn("Could not restore memblockq during move");
212853a5a1b3Sopenharmony_ci            break;
212953a5a1b3Sopenharmony_ci        }
213053a5a1b3Sopenharmony_ci
213153a5a1b3Sopenharmony_ci        if (i->thread_info.resampler) {
213253a5a1b3Sopenharmony_ci            pa_resampler_run(i->thread_info.resampler, &in_chunk, &out_chunk);
213353a5a1b3Sopenharmony_ci            pa_memblock_unref(in_chunk.memblock);
213453a5a1b3Sopenharmony_ci        } else
213553a5a1b3Sopenharmony_ci            out_chunk = in_chunk;
213653a5a1b3Sopenharmony_ci
213753a5a1b3Sopenharmony_ci        if (out_chunk.length > 0) {
213853a5a1b3Sopenharmony_ci            pa_memblockq_push(i->thread_info.render_memblockq, &out_chunk);
213953a5a1b3Sopenharmony_ci            pa_memblock_unref(out_chunk.memblock);
214053a5a1b3Sopenharmony_ci        }
214153a5a1b3Sopenharmony_ci
214253a5a1b3Sopenharmony_ci        pa_memblockq_drop(i->thread_info.history_memblockq, push_bytes);
214353a5a1b3Sopenharmony_ci        to_push -= push_bytes;
214453a5a1b3Sopenharmony_ci    }
214553a5a1b3Sopenharmony_ci
214653a5a1b3Sopenharmony_ci    /* No need to rewind the history queue here, it will be re-synchronized
214753a5a1b3Sopenharmony_ci     * with the render queue during the next pa_sink_input_drop() call. */
214853a5a1b3Sopenharmony_ci
214953a5a1b3Sopenharmony_ci    /* Tell the sink input not to ask the implementer to rewrite during the
215053a5a1b3Sopenharmony_ci     * the next rewind */
215153a5a1b3Sopenharmony_ci    i->thread_info.dont_rewrite = true;
215253a5a1b3Sopenharmony_ci}
215353a5a1b3Sopenharmony_ci
215453a5a1b3Sopenharmony_ci/* Called from main context */
215553a5a1b3Sopenharmony_ciint pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, bool save) {
215653a5a1b3Sopenharmony_ci    struct volume_factor_entry *v;
215753a5a1b3Sopenharmony_ci    void *state = NULL;
215853a5a1b3Sopenharmony_ci
215953a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
216053a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
216153a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
216253a5a1b3Sopenharmony_ci    pa_assert(!i->sink);
216353a5a1b3Sopenharmony_ci    pa_sink_assert_ref(dest);
216453a5a1b3Sopenharmony_ci
216553a5a1b3Sopenharmony_ci    if (!pa_sink_input_may_move_to(i, dest))
216653a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
216753a5a1b3Sopenharmony_ci
216853a5a1b3Sopenharmony_ci    if (pa_sink_input_is_passthrough(i) && !pa_sink_check_format(dest, i->format)) {
216953a5a1b3Sopenharmony_ci        pa_proplist *p = pa_proplist_new();
217053a5a1b3Sopenharmony_ci        pa_log_debug("New sink doesn't support stream format, sending format-changed and killing");
217153a5a1b3Sopenharmony_ci        /* Tell the client what device we want to be on if it is going to
217253a5a1b3Sopenharmony_ci         * reconnect */
217353a5a1b3Sopenharmony_ci        pa_proplist_sets(p, "device", dest->name);
217453a5a1b3Sopenharmony_ci        pa_sink_input_send_event(i, PA_STREAM_EVENT_FORMAT_LOST, p);
217553a5a1b3Sopenharmony_ci        pa_proplist_free(p);
217653a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
217753a5a1b3Sopenharmony_ci    }
217853a5a1b3Sopenharmony_ci
217953a5a1b3Sopenharmony_ci    if (!(i->flags & PA_SINK_INPUT_VARIABLE_RATE) &&
218053a5a1b3Sopenharmony_ci        !pa_sample_spec_equal(&i->sample_spec, &dest->sample_spec)) {
218153a5a1b3Sopenharmony_ci        /* try to change dest sink format and rate if possible without glitches.
218253a5a1b3Sopenharmony_ci           module-suspend-on-idle resumes destination sink with
218353a5a1b3Sopenharmony_ci           SINK_INPUT_MOVE_FINISH hook */
218453a5a1b3Sopenharmony_ci
218553a5a1b3Sopenharmony_ci        pa_log_info("Trying to change sample spec");
218653a5a1b3Sopenharmony_ci        pa_sink_reconfigure(dest, &i->sample_spec, pa_sink_input_is_passthrough(i));
218753a5a1b3Sopenharmony_ci    }
218853a5a1b3Sopenharmony_ci
218953a5a1b3Sopenharmony_ci    if (i->moving)
219053a5a1b3Sopenharmony_ci        i->moving(i, dest);
219153a5a1b3Sopenharmony_ci
219253a5a1b3Sopenharmony_ci    i->sink = dest;
219353a5a1b3Sopenharmony_ci    /* save == true, means user is calling the move_to() and want to
219453a5a1b3Sopenharmony_ci       save the preferred_sink */
219553a5a1b3Sopenharmony_ci    if (save) {
219653a5a1b3Sopenharmony_ci        if (dest == dest->core->default_sink)
219753a5a1b3Sopenharmony_ci            set_preferred_sink(i, NULL);
219853a5a1b3Sopenharmony_ci        else
219953a5a1b3Sopenharmony_ci            set_preferred_sink(i, dest->name);
220053a5a1b3Sopenharmony_ci    }
220153a5a1b3Sopenharmony_ci
220253a5a1b3Sopenharmony_ci    pa_idxset_put(dest->inputs, pa_sink_input_ref(i), NULL);
220353a5a1b3Sopenharmony_ci
220453a5a1b3Sopenharmony_ci    PA_HASHMAP_FOREACH(v, i->volume_factor_sink_items, state)
220553a5a1b3Sopenharmony_ci        pa_cvolume_remap(&v->volume, &i->channel_map, &i->sink->channel_map);
220653a5a1b3Sopenharmony_ci
220753a5a1b3Sopenharmony_ci    pa_cvolume_remap(&i->volume_factor_sink, &i->channel_map, &i->sink->channel_map);
220853a5a1b3Sopenharmony_ci
220953a5a1b3Sopenharmony_ci    if (i->state == PA_SINK_INPUT_CORKED)
221053a5a1b3Sopenharmony_ci        i->sink->n_corked++;
221153a5a1b3Sopenharmony_ci
221253a5a1b3Sopenharmony_ci    pa_sink_input_update_resampler(i, false);
221353a5a1b3Sopenharmony_ci
221453a5a1b3Sopenharmony_ci    // restore_render_memblockq(i); // restore is needless for moving between sinks
221553a5a1b3Sopenharmony_ci
221653a5a1b3Sopenharmony_ci    pa_sink_update_status(dest);
221753a5a1b3Sopenharmony_ci
221853a5a1b3Sopenharmony_ci    update_volume_due_to_moving(i, dest);
221953a5a1b3Sopenharmony_ci
222053a5a1b3Sopenharmony_ci    if (pa_sink_input_is_passthrough(i))
222153a5a1b3Sopenharmony_ci        pa_sink_enter_passthrough(i->sink);
222253a5a1b3Sopenharmony_ci
222353a5a1b3Sopenharmony_ci    pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);
222453a5a1b3Sopenharmony_ci
222553a5a1b3Sopenharmony_ci    /* Reset move variable */
222653a5a1b3Sopenharmony_ci    i->origin_rewind_bytes = 0;
222753a5a1b3Sopenharmony_ci
222853a5a1b3Sopenharmony_ci    pa_log_debug("Successfully moved sink input %i to %s.", i->index, dest->name);
222953a5a1b3Sopenharmony_ci
223053a5a1b3Sopenharmony_ci    /* Notify everyone */
223153a5a1b3Sopenharmony_ci    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
223253a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
223353a5a1b3Sopenharmony_ci
223453a5a1b3Sopenharmony_ci    return 0;
223553a5a1b3Sopenharmony_ci}
223653a5a1b3Sopenharmony_ci
223753a5a1b3Sopenharmony_ci/* Called from main context */
223853a5a1b3Sopenharmony_civoid pa_sink_input_fail_move(pa_sink_input *i) {
223953a5a1b3Sopenharmony_ci
224053a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
224153a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
224253a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
224353a5a1b3Sopenharmony_ci    pa_assert(!i->sink);
224453a5a1b3Sopenharmony_ci
224553a5a1b3Sopenharmony_ci    /* Check if someone wants this sink input? */
224653a5a1b3Sopenharmony_ci    if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FAIL], i) == PA_HOOK_STOP)
224753a5a1b3Sopenharmony_ci        return;
224853a5a1b3Sopenharmony_ci
224953a5a1b3Sopenharmony_ci    /* Can we move the sink input to the default sink? */
225053a5a1b3Sopenharmony_ci    if (i->core->rescue_streams && pa_sink_input_may_move_to(i, i->core->default_sink)) {
225153a5a1b3Sopenharmony_ci        if (pa_sink_input_finish_move(i, i->core->default_sink, false) >= 0)
225253a5a1b3Sopenharmony_ci            return;
225353a5a1b3Sopenharmony_ci    }
225453a5a1b3Sopenharmony_ci
225553a5a1b3Sopenharmony_ci    if (i->moving)
225653a5a1b3Sopenharmony_ci        i->moving(i, NULL);
225753a5a1b3Sopenharmony_ci
225853a5a1b3Sopenharmony_ci    pa_sink_input_kill(i);
225953a5a1b3Sopenharmony_ci}
226053a5a1b3Sopenharmony_ci
226153a5a1b3Sopenharmony_ci/* Called from main context */
226253a5a1b3Sopenharmony_ciint pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest, bool save) {
226353a5a1b3Sopenharmony_ci    int r;
226453a5a1b3Sopenharmony_ci
226553a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
226653a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
226753a5a1b3Sopenharmony_ci    pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
226853a5a1b3Sopenharmony_ci    pa_assert(i->sink);
226953a5a1b3Sopenharmony_ci    pa_sink_assert_ref(dest);
227053a5a1b3Sopenharmony_ci
227153a5a1b3Sopenharmony_ci    if (dest == i->sink)
227253a5a1b3Sopenharmony_ci        return 0;
227353a5a1b3Sopenharmony_ci
227453a5a1b3Sopenharmony_ci    if (!pa_sink_input_may_move_to(i, dest))
227553a5a1b3Sopenharmony_ci        return -PA_ERR_NOTSUPPORTED;
227653a5a1b3Sopenharmony_ci
227753a5a1b3Sopenharmony_ci    pa_sink_input_ref(i);
227853a5a1b3Sopenharmony_ci
227953a5a1b3Sopenharmony_ci    if ((r = pa_sink_input_start_move(i)) < 0) {
228053a5a1b3Sopenharmony_ci        pa_sink_input_unref(i);
228153a5a1b3Sopenharmony_ci        return r;
228253a5a1b3Sopenharmony_ci    }
228353a5a1b3Sopenharmony_ci
228453a5a1b3Sopenharmony_ci    if ((r = pa_sink_input_finish_move(i, dest, save)) < 0) {
228553a5a1b3Sopenharmony_ci        pa_sink_input_fail_move(i);
228653a5a1b3Sopenharmony_ci        pa_sink_input_unref(i);
228753a5a1b3Sopenharmony_ci        return r;
228853a5a1b3Sopenharmony_ci    }
228953a5a1b3Sopenharmony_ci
229053a5a1b3Sopenharmony_ci    pa_sink_input_unref(i);
229153a5a1b3Sopenharmony_ci
229253a5a1b3Sopenharmony_ci    return 0;
229353a5a1b3Sopenharmony_ci}
229453a5a1b3Sopenharmony_ci
229553a5a1b3Sopenharmony_ci/* Called from IO thread context except when cork() is called without a valid sink. */
229653a5a1b3Sopenharmony_civoid pa_sink_input_set_state_within_thread(pa_sink_input *i, pa_sink_input_state_t state) {
229753a5a1b3Sopenharmony_ci    bool corking, uncorking;
229853a5a1b3Sopenharmony_ci
229953a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
230053a5a1b3Sopenharmony_ci
230153a5a1b3Sopenharmony_ci    if (state == i->thread_info.state)
230253a5a1b3Sopenharmony_ci        return;
230353a5a1b3Sopenharmony_ci
230453a5a1b3Sopenharmony_ci    corking = state == PA_SINK_INPUT_CORKED && i->thread_info.state == PA_SINK_INPUT_RUNNING;
230553a5a1b3Sopenharmony_ci    uncorking = i->thread_info.state == PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_RUNNING;
230653a5a1b3Sopenharmony_ci
230753a5a1b3Sopenharmony_ci    if (i->state_change)
230853a5a1b3Sopenharmony_ci        i->state_change(i, state);
230953a5a1b3Sopenharmony_ci
231053a5a1b3Sopenharmony_ci    if (corking) {
231153a5a1b3Sopenharmony_ci
231253a5a1b3Sopenharmony_ci        pa_log_debug("Requesting rewind due to corking");
231353a5a1b3Sopenharmony_ci
231453a5a1b3Sopenharmony_ci        /* This will tell the implementing sink input driver to rewind
231553a5a1b3Sopenharmony_ci         * so that the unplayed already mixed data is not lost */
231653a5a1b3Sopenharmony_ci        if (i->sink)
231753a5a1b3Sopenharmony_ci            pa_sink_input_request_rewind(i, 0, true, true, false);
231853a5a1b3Sopenharmony_ci
231953a5a1b3Sopenharmony_ci        /* Set the corked state *after* requesting rewind */
232053a5a1b3Sopenharmony_ci        i->thread_info.state = state;
232153a5a1b3Sopenharmony_ci
232253a5a1b3Sopenharmony_ci    } else if (uncorking) {
232353a5a1b3Sopenharmony_ci
232453a5a1b3Sopenharmony_ci        pa_log_debug("Requesting rewind due to uncorking");
232553a5a1b3Sopenharmony_ci
232653a5a1b3Sopenharmony_ci        i->thread_info.underrun_for = (uint64_t) -1;
232753a5a1b3Sopenharmony_ci        i->thread_info.underrun_for_sink = 0;
232853a5a1b3Sopenharmony_ci        i->thread_info.playing_for = 0;
232953a5a1b3Sopenharmony_ci
233053a5a1b3Sopenharmony_ci        /* Set the uncorked state *before* requesting rewind */
233153a5a1b3Sopenharmony_ci        i->thread_info.state = state;
233253a5a1b3Sopenharmony_ci
233353a5a1b3Sopenharmony_ci        /* OK, we're being uncorked. Make sure we're not rewound when
233453a5a1b3Sopenharmony_ci         * the hw buffer is remixed and request a remix. */
233553a5a1b3Sopenharmony_ci        if (i->sink)
233653a5a1b3Sopenharmony_ci            pa_sink_input_request_rewind(i, 0, false, true, true);
233753a5a1b3Sopenharmony_ci    } else
233853a5a1b3Sopenharmony_ci        /* We may not be corking or uncorking, but we still need to set the state. */
233953a5a1b3Sopenharmony_ci        i->thread_info.state = state;
234053a5a1b3Sopenharmony_ci}
234153a5a1b3Sopenharmony_ci
234253a5a1b3Sopenharmony_ci/* Called from thread context, except when it is not. */
234353a5a1b3Sopenharmony_ciint pa_sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
234453a5a1b3Sopenharmony_ci    pa_sink_input *i = PA_SINK_INPUT(o);
234553a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
234653a5a1b3Sopenharmony_ci
234753a5a1b3Sopenharmony_ci    switch (code) {
234853a5a1b3Sopenharmony_ci
234953a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_SET_SOFT_VOLUME:
235053a5a1b3Sopenharmony_ci            if (!pa_cvolume_equal(&i->thread_info.soft_volume, &i->soft_volume)) {
235153a5a1b3Sopenharmony_ci                i->thread_info.soft_volume = i->soft_volume;
235253a5a1b3Sopenharmony_ci                pa_sink_input_request_rewind(i, 0, true, false, false);
235353a5a1b3Sopenharmony_ci            }
235453a5a1b3Sopenharmony_ci            return 0;
235553a5a1b3Sopenharmony_ci
235653a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_SET_SOFT_MUTE:
235753a5a1b3Sopenharmony_ci            if (i->thread_info.muted != i->muted) {
235853a5a1b3Sopenharmony_ci                i->thread_info.muted = i->muted;
235953a5a1b3Sopenharmony_ci                pa_sink_input_request_rewind(i, 0, true, false, false);
236053a5a1b3Sopenharmony_ci            }
236153a5a1b3Sopenharmony_ci            return 0;
236253a5a1b3Sopenharmony_ci
236353a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_GET_LATENCY: {
236453a5a1b3Sopenharmony_ci            pa_usec_t *r = userdata;
236553a5a1b3Sopenharmony_ci
236653a5a1b3Sopenharmony_ci            r[0] += pa_bytes_to_usec(pa_memblockq_get_length(i->thread_info.render_memblockq), &i->sink->sample_spec);
236753a5a1b3Sopenharmony_ci            r[0] += pa_resampler_get_delay_usec(i->thread_info.resampler);
236853a5a1b3Sopenharmony_ci            r[1] += pa_sink_get_latency_within_thread(i->sink, false);
236953a5a1b3Sopenharmony_ci
237053a5a1b3Sopenharmony_ci            return 0;
237153a5a1b3Sopenharmony_ci        }
237253a5a1b3Sopenharmony_ci
237353a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_SET_RATE:
237453a5a1b3Sopenharmony_ci
237553a5a1b3Sopenharmony_ci            i->thread_info.sample_spec.rate = PA_PTR_TO_UINT(userdata);
237653a5a1b3Sopenharmony_ci            pa_resampler_set_input_rate(i->thread_info.resampler, PA_PTR_TO_UINT(userdata));
237753a5a1b3Sopenharmony_ci
237853a5a1b3Sopenharmony_ci            return 0;
237953a5a1b3Sopenharmony_ci
238053a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_SET_STATE: {
238153a5a1b3Sopenharmony_ci            pa_sink_input *ssync;
238253a5a1b3Sopenharmony_ci
238353a5a1b3Sopenharmony_ci            pa_sink_input_set_state_within_thread(i, PA_PTR_TO_UINT(userdata));
238453a5a1b3Sopenharmony_ci
238553a5a1b3Sopenharmony_ci            for (ssync = i->thread_info.sync_prev; ssync; ssync = ssync->thread_info.sync_prev)
238653a5a1b3Sopenharmony_ci                pa_sink_input_set_state_within_thread(ssync, PA_PTR_TO_UINT(userdata));
238753a5a1b3Sopenharmony_ci
238853a5a1b3Sopenharmony_ci            for (ssync = i->thread_info.sync_next; ssync; ssync = ssync->thread_info.sync_next)
238953a5a1b3Sopenharmony_ci                pa_sink_input_set_state_within_thread(ssync, PA_PTR_TO_UINT(userdata));
239053a5a1b3Sopenharmony_ci
239153a5a1b3Sopenharmony_ci            return 0;
239253a5a1b3Sopenharmony_ci        }
239353a5a1b3Sopenharmony_ci
239453a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY: {
239553a5a1b3Sopenharmony_ci            pa_usec_t *usec = userdata;
239653a5a1b3Sopenharmony_ci
239753a5a1b3Sopenharmony_ci            *usec = pa_sink_input_set_requested_latency_within_thread(i, *usec);
239853a5a1b3Sopenharmony_ci            return 0;
239953a5a1b3Sopenharmony_ci        }
240053a5a1b3Sopenharmony_ci
240153a5a1b3Sopenharmony_ci        case PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY: {
240253a5a1b3Sopenharmony_ci            pa_usec_t *r = userdata;
240353a5a1b3Sopenharmony_ci
240453a5a1b3Sopenharmony_ci            *r = i->thread_info.requested_sink_latency;
240553a5a1b3Sopenharmony_ci            return 0;
240653a5a1b3Sopenharmony_ci        }
240753a5a1b3Sopenharmony_ci    }
240853a5a1b3Sopenharmony_ci
240953a5a1b3Sopenharmony_ci    return -PA_ERR_NOTIMPLEMENTED;
241053a5a1b3Sopenharmony_ci}
241153a5a1b3Sopenharmony_ci
241253a5a1b3Sopenharmony_ci/* Called from IO context */
241353a5a1b3Sopenharmony_cibool pa_sink_input_safe_to_remove(pa_sink_input *i) {
241453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
241553a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
241653a5a1b3Sopenharmony_ci
241753a5a1b3Sopenharmony_ci    if (PA_SINK_INPUT_IS_LINKED(i->thread_info.state))
241853a5a1b3Sopenharmony_ci        return pa_memblockq_is_empty(i->thread_info.render_memblockq);
241953a5a1b3Sopenharmony_ci
242053a5a1b3Sopenharmony_ci    return true;
242153a5a1b3Sopenharmony_ci}
242253a5a1b3Sopenharmony_ci
242353a5a1b3Sopenharmony_ci/* Called from IO context */
242453a5a1b3Sopenharmony_civoid pa_sink_input_request_rewind(
242553a5a1b3Sopenharmony_ci        pa_sink_input *i,
242653a5a1b3Sopenharmony_ci        size_t nbytes  /* in our sample spec */,
242753a5a1b3Sopenharmony_ci        bool rewrite,  /* rewrite what we have, or get fresh data? */
242853a5a1b3Sopenharmony_ci        bool flush,    /* flush render memblockq? */
242953a5a1b3Sopenharmony_ci        bool dont_rewind_render) {
243053a5a1b3Sopenharmony_ci
243153a5a1b3Sopenharmony_ci    size_t lbq;
243253a5a1b3Sopenharmony_ci
243353a5a1b3Sopenharmony_ci    /* If 'rewrite' is true the sink is rewound as far as requested
243453a5a1b3Sopenharmony_ci     * and possible and the exact value of this is passed back the
243553a5a1b3Sopenharmony_ci     * implementor via process_rewind(). If 'flush' is also true all
243653a5a1b3Sopenharmony_ci     * already rendered data is also dropped.
243753a5a1b3Sopenharmony_ci     *
243853a5a1b3Sopenharmony_ci     * If 'rewrite' is false the sink is rewound as far as requested
243953a5a1b3Sopenharmony_ci     * and possible and the already rendered data is dropped so that
244053a5a1b3Sopenharmony_ci     * in the next iteration we read new data from the
244153a5a1b3Sopenharmony_ci     * implementor. This implies 'flush' is true.  If
244253a5a1b3Sopenharmony_ci     * dont_rewind_render is true then the render memblockq is not
244353a5a1b3Sopenharmony_ci     * rewound. */
244453a5a1b3Sopenharmony_ci
244553a5a1b3Sopenharmony_ci    /* nbytes = 0 means maximum rewind request */
244653a5a1b3Sopenharmony_ci
244753a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
244853a5a1b3Sopenharmony_ci    pa_sink_input_assert_io_context(i);
244953a5a1b3Sopenharmony_ci    pa_assert(rewrite || flush);
245053a5a1b3Sopenharmony_ci    pa_assert(!dont_rewind_render || !rewrite);
245153a5a1b3Sopenharmony_ci
245253a5a1b3Sopenharmony_ci    /* We don't take rewind requests while we are corked */
245353a5a1b3Sopenharmony_ci    if (i->thread_info.state == PA_SINK_INPUT_CORKED)
245453a5a1b3Sopenharmony_ci        return;
245553a5a1b3Sopenharmony_ci
245653a5a1b3Sopenharmony_ci    nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes);
245753a5a1b3Sopenharmony_ci
245853a5a1b3Sopenharmony_ci#ifdef SINK_INPUT_DEBUG
245953a5a1b3Sopenharmony_ci    pa_log_debug("request rewrite %zu", nbytes);
246053a5a1b3Sopenharmony_ci#endif
246153a5a1b3Sopenharmony_ci
246253a5a1b3Sopenharmony_ci    /* Calculate how much we can rewind locally without having to
246353a5a1b3Sopenharmony_ci     * touch the sink */
246453a5a1b3Sopenharmony_ci    if (rewrite)
246553a5a1b3Sopenharmony_ci        lbq = pa_memblockq_get_length(i->thread_info.render_memblockq);
246653a5a1b3Sopenharmony_ci    else
246753a5a1b3Sopenharmony_ci        lbq = 0;
246853a5a1b3Sopenharmony_ci
246953a5a1b3Sopenharmony_ci    /* Check if rewinding for the maximum is requested, and if so, fix up */
247053a5a1b3Sopenharmony_ci    if (nbytes <= 0) {
247153a5a1b3Sopenharmony_ci
247253a5a1b3Sopenharmony_ci        /* Calculate maximum number of bytes that could be rewound in theory.
247353a5a1b3Sopenharmony_ci         * If the sink has a virtual sink attached, limit rewinding to max_rewind.
247453a5a1b3Sopenharmony_ci         *
247553a5a1b3Sopenharmony_ci         * The max_rewind value of a virtual sink depends on the rewinding capability
247653a5a1b3Sopenharmony_ci         * of its DSP code. The DSP code is rewound in the process_rewind() callback
247753a5a1b3Sopenharmony_ci         * of the sink input. Therefore rewinding must be limited to max_rewind here. */
247853a5a1b3Sopenharmony_ci        nbytes = i->sink->thread_info.max_rewind;
247953a5a1b3Sopenharmony_ci        if (!pa_sink_has_filter_attached(i->sink) && !pa_sink_is_filter(i->sink))
248053a5a1b3Sopenharmony_ci            nbytes += lbq;
248153a5a1b3Sopenharmony_ci
248253a5a1b3Sopenharmony_ci        /* Transform from sink domain */
248353a5a1b3Sopenharmony_ci        nbytes = pa_resampler_request(i->thread_info.resampler, nbytes);
248453a5a1b3Sopenharmony_ci    }
248553a5a1b3Sopenharmony_ci
248653a5a1b3Sopenharmony_ci    /* For virtual sinks there are two situations where nbytes may exceed max_rewind:
248753a5a1b3Sopenharmony_ci     * 1) If an underrun was detected.
248853a5a1b3Sopenharmony_ci     * 2) When the sink input is rewound during a move when it is attached to
248953a5a1b3Sopenharmony_ci     *    the destination sink.
249053a5a1b3Sopenharmony_ci     * Moving a sink input is handled without involving the implementer, so the
249153a5a1b3Sopenharmony_ci     * implementer will only be asked to rewind more than max_rewind if an
249253a5a1b3Sopenharmony_ci     * underrun occurs. In that case, the DSP code of virtual sinks should be
249353a5a1b3Sopenharmony_ci     * reset instead of rewound. Therefore the rewind function of filters should
249453a5a1b3Sopenharmony_ci     * check if the requested rewind exceeds the maximum possible rewind of the
249553a5a1b3Sopenharmony_ci     * filter. */
249653a5a1b3Sopenharmony_ci
249753a5a1b3Sopenharmony_ci    /* Remember how much we actually want to rewrite */
249853a5a1b3Sopenharmony_ci    if (i->thread_info.rewrite_nbytes != (size_t) -1) {
249953a5a1b3Sopenharmony_ci        if (rewrite) {
250053a5a1b3Sopenharmony_ci            /* Make sure to not overwrite over underruns */
250153a5a1b3Sopenharmony_ci            if (nbytes > i->thread_info.playing_for)
250253a5a1b3Sopenharmony_ci                nbytes = (size_t) i->thread_info.playing_for;
250353a5a1b3Sopenharmony_ci
250453a5a1b3Sopenharmony_ci            i->thread_info.rewrite_nbytes = nbytes;
250553a5a1b3Sopenharmony_ci        } else
250653a5a1b3Sopenharmony_ci            i->thread_info.rewrite_nbytes = (size_t) -1;
250753a5a1b3Sopenharmony_ci    }
250853a5a1b3Sopenharmony_ci
250953a5a1b3Sopenharmony_ci    i->thread_info.rewrite_flush =
251053a5a1b3Sopenharmony_ci        i->thread_info.rewrite_flush || flush;
251153a5a1b3Sopenharmony_ci
251253a5a1b3Sopenharmony_ci    i->thread_info.dont_rewind_render =
251353a5a1b3Sopenharmony_ci        i->thread_info.dont_rewind_render ||
251453a5a1b3Sopenharmony_ci        dont_rewind_render;
251553a5a1b3Sopenharmony_ci
251653a5a1b3Sopenharmony_ci    /* nbytes is -1 if some earlier rewind request had rewrite == false. */
251753a5a1b3Sopenharmony_ci    if (nbytes != (size_t) -1) {
251853a5a1b3Sopenharmony_ci
251953a5a1b3Sopenharmony_ci        /* Transform to sink domain */
252053a5a1b3Sopenharmony_ci        nbytes = pa_resampler_result(i->thread_info.resampler, nbytes);
252153a5a1b3Sopenharmony_ci
252253a5a1b3Sopenharmony_ci        if (nbytes > lbq)
252353a5a1b3Sopenharmony_ci            pa_sink_request_rewind(i->sink, nbytes - lbq);
252453a5a1b3Sopenharmony_ci        else
252553a5a1b3Sopenharmony_ci            /* This call will make sure process_rewind() is called later */
252653a5a1b3Sopenharmony_ci            pa_sink_request_rewind(i->sink, 0);
252753a5a1b3Sopenharmony_ci    }
252853a5a1b3Sopenharmony_ci}
252953a5a1b3Sopenharmony_ci
253053a5a1b3Sopenharmony_ci/* Called from main context */
253153a5a1b3Sopenharmony_cipa_memchunk* pa_sink_input_get_silence(pa_sink_input *i, pa_memchunk *ret) {
253253a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
253353a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
253453a5a1b3Sopenharmony_ci    pa_assert(ret);
253553a5a1b3Sopenharmony_ci
253653a5a1b3Sopenharmony_ci    /* FIXME: Shouldn't access resampler object from main context! */
253753a5a1b3Sopenharmony_ci
253853a5a1b3Sopenharmony_ci    pa_silence_memchunk_get(
253953a5a1b3Sopenharmony_ci                &i->core->silence_cache,
254053a5a1b3Sopenharmony_ci                i->core->mempool,
254153a5a1b3Sopenharmony_ci                ret,
254253a5a1b3Sopenharmony_ci                &i->sample_spec,
254353a5a1b3Sopenharmony_ci                i->thread_info.resampler ? pa_resampler_max_block_size(i->thread_info.resampler) : 0);
254453a5a1b3Sopenharmony_ci
254553a5a1b3Sopenharmony_ci    return ret;
254653a5a1b3Sopenharmony_ci}
254753a5a1b3Sopenharmony_ci
254853a5a1b3Sopenharmony_ci/* Called from main context */
254953a5a1b3Sopenharmony_civoid pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) {
255053a5a1b3Sopenharmony_ci    pa_proplist *pl = NULL;
255153a5a1b3Sopenharmony_ci    pa_sink_input_send_event_hook_data hook_data;
255253a5a1b3Sopenharmony_ci
255353a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
255453a5a1b3Sopenharmony_ci    // pa_assert_ctl_context();
255553a5a1b3Sopenharmony_ci    pa_assert(event);
255653a5a1b3Sopenharmony_ci
255753a5a1b3Sopenharmony_ci    if (!i->send_event)
255853a5a1b3Sopenharmony_ci        return;
255953a5a1b3Sopenharmony_ci
256053a5a1b3Sopenharmony_ci    if (!data)
256153a5a1b3Sopenharmony_ci        data = pl = pa_proplist_new();
256253a5a1b3Sopenharmony_ci
256353a5a1b3Sopenharmony_ci    hook_data.sink_input = i;
256453a5a1b3Sopenharmony_ci    hook_data.data = data;
256553a5a1b3Sopenharmony_ci    hook_data.event = event;
256653a5a1b3Sopenharmony_ci
256753a5a1b3Sopenharmony_ci    if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0)
256853a5a1b3Sopenharmony_ci        goto finish;
256953a5a1b3Sopenharmony_ci
257053a5a1b3Sopenharmony_ci    i->send_event(i, event, data);
257153a5a1b3Sopenharmony_ci
257253a5a1b3Sopenharmony_cifinish:
257353a5a1b3Sopenharmony_ci    if (pl)
257453a5a1b3Sopenharmony_ci        pa_proplist_free(pl);
257553a5a1b3Sopenharmony_ci}
257653a5a1b3Sopenharmony_ci
257753a5a1b3Sopenharmony_ci/* Called from main context */
257853a5a1b3Sopenharmony_ci/* Updates the sink input's resampler with whatever the current sink requires
257953a5a1b3Sopenharmony_ci * -- useful when the underlying sink's sample spec might have changed */
258053a5a1b3Sopenharmony_ciint pa_sink_input_update_resampler(pa_sink_input *i, bool flush_history) {
258153a5a1b3Sopenharmony_ci    pa_resampler *new_resampler;
258253a5a1b3Sopenharmony_ci    char *memblockq_name;
258353a5a1b3Sopenharmony_ci
258453a5a1b3Sopenharmony_ci    pa_sink_input_assert_ref(i);
258553a5a1b3Sopenharmony_ci    pa_assert_ctl_context();
258653a5a1b3Sopenharmony_ci
258753a5a1b3Sopenharmony_ci    if (i->thread_info.resampler &&
258853a5a1b3Sopenharmony_ci        pa_sample_spec_equal(pa_resampler_output_sample_spec(i->thread_info.resampler), &i->sink->sample_spec) &&
258953a5a1b3Sopenharmony_ci        pa_channel_map_equal(pa_resampler_output_channel_map(i->thread_info.resampler), &i->sink->channel_map))
259053a5a1b3Sopenharmony_ci
259153a5a1b3Sopenharmony_ci        new_resampler = i->thread_info.resampler;
259253a5a1b3Sopenharmony_ci
259353a5a1b3Sopenharmony_ci    else if (!pa_sink_input_is_passthrough(i) &&
259453a5a1b3Sopenharmony_ci        ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ||
259553a5a1b3Sopenharmony_ci         !pa_sample_spec_equal(&i->sample_spec, &i->sink->sample_spec) ||
259653a5a1b3Sopenharmony_ci         !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map))) {
259753a5a1b3Sopenharmony_ci
259853a5a1b3Sopenharmony_ci        new_resampler = pa_resampler_new(i->core->mempool,
259953a5a1b3Sopenharmony_ci                                     &i->sample_spec, &i->channel_map,
260053a5a1b3Sopenharmony_ci                                     &i->sink->sample_spec, &i->sink->channel_map,
260153a5a1b3Sopenharmony_ci                                     i->core->lfe_crossover_freq,
260253a5a1b3Sopenharmony_ci                                     i->requested_resample_method,
260353a5a1b3Sopenharmony_ci                                     ((i->flags & PA_SINK_INPUT_VARIABLE_RATE) ? PA_RESAMPLER_VARIABLE_RATE : 0) |
260453a5a1b3Sopenharmony_ci                                     ((i->flags & PA_SINK_INPUT_NO_REMAP) ? PA_RESAMPLER_NO_REMAP : 0) |
260553a5a1b3Sopenharmony_ci                                     (i->core->disable_remixing || (i->flags & PA_SINK_INPUT_NO_REMIX) ? PA_RESAMPLER_NO_REMIX : 0) |
260653a5a1b3Sopenharmony_ci                                     (i->core->remixing_use_all_sink_channels ? 0 : PA_RESAMPLER_NO_FILL_SINK) |
260753a5a1b3Sopenharmony_ci                                     (i->core->remixing_produce_lfe ? PA_RESAMPLER_PRODUCE_LFE : 0) |
260853a5a1b3Sopenharmony_ci                                     (i->core->remixing_consume_lfe ? PA_RESAMPLER_CONSUME_LFE : 0));
260953a5a1b3Sopenharmony_ci
261053a5a1b3Sopenharmony_ci        if (!new_resampler) {
261153a5a1b3Sopenharmony_ci            pa_log_warn("Unsupported resampling operation.");
261253a5a1b3Sopenharmony_ci            return -PA_ERR_NOTSUPPORTED;
261353a5a1b3Sopenharmony_ci        }
261453a5a1b3Sopenharmony_ci    } else
261553a5a1b3Sopenharmony_ci        new_resampler = NULL;
261653a5a1b3Sopenharmony_ci
261753a5a1b3Sopenharmony_ci    if (flush_history)
261853a5a1b3Sopenharmony_ci        pa_memblockq_flush_write(i->thread_info.history_memblockq, true);
261953a5a1b3Sopenharmony_ci
262053a5a1b3Sopenharmony_ci    if (new_resampler == i->thread_info.resampler)
262153a5a1b3Sopenharmony_ci        return 0;
262253a5a1b3Sopenharmony_ci
262353a5a1b3Sopenharmony_ci    if (i->thread_info.resampler)
262453a5a1b3Sopenharmony_ci        pa_resampler_free(i->thread_info.resampler);
262553a5a1b3Sopenharmony_ci
262653a5a1b3Sopenharmony_ci    i->thread_info.resampler = new_resampler;
262753a5a1b3Sopenharmony_ci
262853a5a1b3Sopenharmony_ci    pa_memblockq_free(i->thread_info.render_memblockq);
262953a5a1b3Sopenharmony_ci
263053a5a1b3Sopenharmony_ci    memblockq_name = pa_sprintf_malloc("sink input render_memblockq [%u]", i->index);
263153a5a1b3Sopenharmony_ci    i->thread_info.render_memblockq = pa_memblockq_new(
263253a5a1b3Sopenharmony_ci            memblockq_name,
263353a5a1b3Sopenharmony_ci            0,
263453a5a1b3Sopenharmony_ci            MEMBLOCKQ_MAXLENGTH,
263553a5a1b3Sopenharmony_ci            0,
263653a5a1b3Sopenharmony_ci            &i->sink->sample_spec,
263753a5a1b3Sopenharmony_ci            0,
263853a5a1b3Sopenharmony_ci            1,
263953a5a1b3Sopenharmony_ci            0,
264053a5a1b3Sopenharmony_ci            &i->sink->silence);
264153a5a1b3Sopenharmony_ci    pa_xfree(memblockq_name);
264253a5a1b3Sopenharmony_ci
264353a5a1b3Sopenharmony_ci    i->actual_resample_method = new_resampler ? pa_resampler_get_method(new_resampler) : PA_RESAMPLER_INVALID;
264453a5a1b3Sopenharmony_ci
264553a5a1b3Sopenharmony_ci    pa_log_debug("Updated resampler for sink input %d", i->index);
264653a5a1b3Sopenharmony_ci
264753a5a1b3Sopenharmony_ci    return 0;
264853a5a1b3Sopenharmony_ci}
264953a5a1b3Sopenharmony_ci
265053a5a1b3Sopenharmony_ci/* Called from the IO thread. */
265153a5a1b3Sopenharmony_civoid pa_sink_input_attach(pa_sink_input *i) {
265253a5a1b3Sopenharmony_ci    pa_assert(i);
265353a5a1b3Sopenharmony_ci    pa_assert(!i->thread_info.attached);
265453a5a1b3Sopenharmony_ci
265553a5a1b3Sopenharmony_ci    i->thread_info.attached = true;
265653a5a1b3Sopenharmony_ci
265753a5a1b3Sopenharmony_ci    if (i->attach)
265853a5a1b3Sopenharmony_ci        i->attach(i);
265953a5a1b3Sopenharmony_ci}
266053a5a1b3Sopenharmony_ci
266153a5a1b3Sopenharmony_ci/* Called from the IO thread. */
266253a5a1b3Sopenharmony_civoid pa_sink_input_detach(pa_sink_input *i) {
266353a5a1b3Sopenharmony_ci    pa_assert(i);
266453a5a1b3Sopenharmony_ci
266553a5a1b3Sopenharmony_ci    if (!i->thread_info.attached)
266653a5a1b3Sopenharmony_ci        return;
266753a5a1b3Sopenharmony_ci
266853a5a1b3Sopenharmony_ci    i->thread_info.attached = false;
266953a5a1b3Sopenharmony_ci
267053a5a1b3Sopenharmony_ci    if (i->detach)
267153a5a1b3Sopenharmony_ci        i->detach(i);
267253a5a1b3Sopenharmony_ci}
267353a5a1b3Sopenharmony_ci
267453a5a1b3Sopenharmony_ci/* Called from the main thread. */
267553a5a1b3Sopenharmony_civoid pa_sink_input_set_volume_direct(pa_sink_input *i, const pa_cvolume *volume) {
267653a5a1b3Sopenharmony_ci    pa_cvolume old_volume;
267753a5a1b3Sopenharmony_ci    char old_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
267853a5a1b3Sopenharmony_ci    char new_volume_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
267953a5a1b3Sopenharmony_ci
268053a5a1b3Sopenharmony_ci    pa_assert(i);
268153a5a1b3Sopenharmony_ci    pa_assert(volume);
268253a5a1b3Sopenharmony_ci
268353a5a1b3Sopenharmony_ci    old_volume = i->volume;
268453a5a1b3Sopenharmony_ci
268553a5a1b3Sopenharmony_ci    if (pa_cvolume_equal(volume, &old_volume))
268653a5a1b3Sopenharmony_ci        return;
268753a5a1b3Sopenharmony_ci
268853a5a1b3Sopenharmony_ci    i->volume = *volume;
268953a5a1b3Sopenharmony_ci    pa_log_debug("The volume of sink input %u changed from %s to %s.", i->index,
269053a5a1b3Sopenharmony_ci                 pa_cvolume_snprint_verbose(old_volume_str, sizeof(old_volume_str), &old_volume, &i->channel_map, true),
269153a5a1b3Sopenharmony_ci                 pa_cvolume_snprint_verbose(new_volume_str, sizeof(new_volume_str), volume, &i->channel_map, true));
269253a5a1b3Sopenharmony_ci
269353a5a1b3Sopenharmony_ci    if (i->volume_changed)
269453a5a1b3Sopenharmony_ci        i->volume_changed(i);
269553a5a1b3Sopenharmony_ci
269653a5a1b3Sopenharmony_ci    pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
269753a5a1b3Sopenharmony_ci    pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_VOLUME_CHANGED], i);
269853a5a1b3Sopenharmony_ci}
269953a5a1b3Sopenharmony_ci
270053a5a1b3Sopenharmony_ci/* Called from the main thread. */
270153a5a1b3Sopenharmony_civoid pa_sink_input_set_reference_ratio(pa_sink_input *i, const pa_cvolume *ratio) {
270253a5a1b3Sopenharmony_ci    pa_cvolume old_ratio;
270353a5a1b3Sopenharmony_ci    char old_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
270453a5a1b3Sopenharmony_ci    char new_ratio_str[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
270553a5a1b3Sopenharmony_ci
270653a5a1b3Sopenharmony_ci    pa_assert(i);
270753a5a1b3Sopenharmony_ci    pa_assert(ratio);
270853a5a1b3Sopenharmony_ci
270953a5a1b3Sopenharmony_ci    old_ratio = i->reference_ratio;
271053a5a1b3Sopenharmony_ci
271153a5a1b3Sopenharmony_ci    if (pa_cvolume_equal(ratio, &old_ratio))
271253a5a1b3Sopenharmony_ci        return;
271353a5a1b3Sopenharmony_ci
271453a5a1b3Sopenharmony_ci    i->reference_ratio = *ratio;
271553a5a1b3Sopenharmony_ci
271653a5a1b3Sopenharmony_ci    if (!PA_SINK_INPUT_IS_LINKED(i->state))
271753a5a1b3Sopenharmony_ci        return;
271853a5a1b3Sopenharmony_ci
271953a5a1b3Sopenharmony_ci    pa_log_debug("Sink input %u reference ratio changed from %s to %s.", i->index,
272053a5a1b3Sopenharmony_ci                 pa_cvolume_snprint_verbose(old_ratio_str, sizeof(old_ratio_str), &old_ratio, &i->channel_map, true),
272153a5a1b3Sopenharmony_ci                 pa_cvolume_snprint_verbose(new_ratio_str, sizeof(new_ratio_str), ratio, &i->channel_map, true));
272253a5a1b3Sopenharmony_ci}
272353a5a1b3Sopenharmony_ci
272453a5a1b3Sopenharmony_ci/* Called from the main thread.
272553a5a1b3Sopenharmony_ci *
272653a5a1b3Sopenharmony_ci * This is called when e.g. module-stream-restore wants to change the preferred
272753a5a1b3Sopenharmony_ci * sink. As a side effect the stream is moved to the new preferred sink. Note
272853a5a1b3Sopenharmony_ci * that things can work also in the other direction: if the user moves
272953a5a1b3Sopenharmony_ci * a stream, as a side effect the preferred sink is changed. This could cause
273053a5a1b3Sopenharmony_ci * an infinite loop, but it's avoided by these two measures:
273153a5a1b3Sopenharmony_ci *   - When pa_sink_input_set_preferred_sink() is called, it calls
273253a5a1b3Sopenharmony_ci *     pa_sink_input_move_to() with save=false, which avoids the recursive
273353a5a1b3Sopenharmony_ci *     pa_sink_input_set_preferred_sink() call.
273453a5a1b3Sopenharmony_ci *   - When the primary operation is to move a stream,
273553a5a1b3Sopenharmony_ci *     pa_sink_input_finish_move() calls set_preferred_sink() instead of
273653a5a1b3Sopenharmony_ci *     pa_sink_input_set_preferred_sink(). set_preferred_sink() doesn't move
273753a5a1b3Sopenharmony_ci *     the stream as a side effect.
273853a5a1b3Sopenharmony_ci */
273953a5a1b3Sopenharmony_civoid pa_sink_input_set_preferred_sink(pa_sink_input *i, pa_sink *s) {
274053a5a1b3Sopenharmony_ci    pa_assert(i);
274153a5a1b3Sopenharmony_ci
274253a5a1b3Sopenharmony_ci    if (s) {
274353a5a1b3Sopenharmony_ci        set_preferred_sink(i, s->name);
274453a5a1b3Sopenharmony_ci        pa_sink_input_move_to(i, s, false);
274553a5a1b3Sopenharmony_ci    } else {
274653a5a1b3Sopenharmony_ci        set_preferred_sink(i, NULL);
274753a5a1b3Sopenharmony_ci        pa_sink_input_move_to(i, i->core->default_sink, false);
274853a5a1b3Sopenharmony_ci    }
274953a5a1b3Sopenharmony_ci}
275053a5a1b3Sopenharmony_ci
275153a5a1b3Sopenharmony_civoid pa_sink_input_handle_ohos_underrun(pa_sink_input *i) {
275253a5a1b3Sopenharmony_ci    if (i->process_underrun_ohos && (pa_atomic_load(&i->isFirstReaded) == 1)) {
275353a5a1b3Sopenharmony_ci        i->process_underrun_ohos(i);
275453a5a1b3Sopenharmony_ci    }
275553a5a1b3Sopenharmony_ci}
2756