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