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#ifndef LOG_TAG 2653a5a1b3Sopenharmony_ci#define LOG_TAG "ProtocolNative" 2753a5a1b3Sopenharmony_ci#endif 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <string.h> 3053a5a1b3Sopenharmony_ci#include <stdio.h> 3153a5a1b3Sopenharmony_ci#include <stdlib.h> 3253a5a1b3Sopenharmony_ci#include <unistd.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 3553a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 3653a5a1b3Sopenharmony_ci#include <pulse/version.h> 3753a5a1b3Sopenharmony_ci#include <pulse/utf8.h> 3853a5a1b3Sopenharmony_ci#include <pulse/util.h> 3953a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4053a5a1b3Sopenharmony_ci#include <pulse/internal.h> 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci#include <pulsecore/native-common.h> 4353a5a1b3Sopenharmony_ci#include <pulsecore/packet.h> 4453a5a1b3Sopenharmony_ci#include <pulsecore/client.h> 4553a5a1b3Sopenharmony_ci#include <pulsecore/source-output.h> 4653a5a1b3Sopenharmony_ci#include <pulsecore/sink-input.h> 4753a5a1b3Sopenharmony_ci#include <pulsecore/pstream.h> 4853a5a1b3Sopenharmony_ci#include <pulsecore/tagstruct.h> 4953a5a1b3Sopenharmony_ci#include <pulsecore/pdispatch.h> 5053a5a1b3Sopenharmony_ci#include <pulsecore/pstream-util.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/namereg.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/core-scache.h> 5353a5a1b3Sopenharmony_ci#include <pulsecore/core-subscribe.h> 5453a5a1b3Sopenharmony_ci#include <pulsecore/message-handler.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/mem.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/strlist.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/shared.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/sample-util.h> 6053a5a1b3Sopenharmony_ci#include <pulsecore/creds.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 6253a5a1b3Sopenharmony_ci#include <pulsecore/ipacl.h> 6353a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h> 6453a5a1b3Sopenharmony_ci#include <pulsecore/mem.h> 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci#include "protocol-native.h" 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci/* #define PROTOCOL_NATIVE_DEBUG */ 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci/* Kick a client if it doesn't authenticate within this time */ 7153a5a1b3Sopenharmony_ci#define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC) 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci/* Don't accept more connection than this */ 7453a5a1b3Sopenharmony_ci#define MAX_CONNECTIONS 128 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */ 7753a5a1b3Sopenharmony_ci#define DEFAULT_TLENGTH_MSEC 2000 /* 2s */ 7853a5a1b3Sopenharmony_ci#define DEFAULT_PROCESS_MSEC 20 /* 20ms */ 7953a5a1b3Sopenharmony_ci#define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC 8053a5a1b3Sopenharmony_ci 8153a5a1b3Sopenharmony_cistatic bool sink_input_process_underrun_cb(pa_sink_input *i); 8253a5a1b3Sopenharmony_cistatic bool sink_input_process_underrun_ohos_cb(pa_sink_input *i); 8353a5a1b3Sopenharmony_cistatic int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk); 8453a5a1b3Sopenharmony_cistatic void sink_input_kill_cb(pa_sink_input *i); 8553a5a1b3Sopenharmony_cistatic void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause); 8653a5a1b3Sopenharmony_cistatic void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest); 8753a5a1b3Sopenharmony_cistatic void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes); 8853a5a1b3Sopenharmony_cistatic void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes); 8953a5a1b3Sopenharmony_cistatic void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes); 9053a5a1b3Sopenharmony_cistatic void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl); 9153a5a1b3Sopenharmony_ci 9253a5a1b3Sopenharmony_cistatic void native_connection_send_memblock(pa_native_connection *c); 9353a5a1b3Sopenharmony_ci 9453a5a1b3Sopenharmony_cistatic void source_output_kill_cb(pa_source_output *o); 9553a5a1b3Sopenharmony_cistatic void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk); 9653a5a1b3Sopenharmony_cistatic void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause); 9753a5a1b3Sopenharmony_cistatic void source_output_moving_cb(pa_source_output *o, pa_source *dest); 9853a5a1b3Sopenharmony_cistatic pa_usec_t source_output_get_latency_cb(pa_source_output *o); 9953a5a1b3Sopenharmony_cistatic void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl); 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_cistatic int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); 10253a5a1b3Sopenharmony_cistatic int source_output_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk); 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci/* structure management */ 10553a5a1b3Sopenharmony_ci 10653a5a1b3Sopenharmony_ci/* Called from main context */ 10753a5a1b3Sopenharmony_cistatic void upload_stream_unlink(upload_stream *s) { 10853a5a1b3Sopenharmony_ci pa_assert(s); 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ci if (!s->connection) 11153a5a1b3Sopenharmony_ci return; 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s); 11453a5a1b3Sopenharmony_ci s->connection = NULL; 11553a5a1b3Sopenharmony_ci upload_stream_unref(s); 11653a5a1b3Sopenharmony_ci} 11753a5a1b3Sopenharmony_ci 11853a5a1b3Sopenharmony_ci/* Called from main context */ 11953a5a1b3Sopenharmony_cistatic void upload_stream_free(pa_object *o) { 12053a5a1b3Sopenharmony_ci upload_stream *s = UPLOAD_STREAM(o); 12153a5a1b3Sopenharmony_ci pa_assert(s); 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci upload_stream_unlink(s); 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci pa_xfree(s->name); 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci if (s->proplist) 12853a5a1b3Sopenharmony_ci pa_proplist_free(s->proplist); 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci if (s->memchunk.memblock) 13153a5a1b3Sopenharmony_ci pa_memblock_unref(s->memchunk.memblock); 13253a5a1b3Sopenharmony_ci 13353a5a1b3Sopenharmony_ci pa_xfree(s); 13453a5a1b3Sopenharmony_ci} 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci/* Called from main context */ 13753a5a1b3Sopenharmony_cistatic upload_stream* upload_stream_new( 13853a5a1b3Sopenharmony_ci pa_native_connection *c, 13953a5a1b3Sopenharmony_ci const pa_sample_spec *ss, 14053a5a1b3Sopenharmony_ci const pa_channel_map *map, 14153a5a1b3Sopenharmony_ci const char *name, 14253a5a1b3Sopenharmony_ci size_t length, 14353a5a1b3Sopenharmony_ci pa_proplist *p) { 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci upload_stream *s; 14653a5a1b3Sopenharmony_ci 14753a5a1b3Sopenharmony_ci pa_assert(c); 14853a5a1b3Sopenharmony_ci pa_assert(ss); 14953a5a1b3Sopenharmony_ci pa_assert(name); 15053a5a1b3Sopenharmony_ci pa_assert(length > 0); 15153a5a1b3Sopenharmony_ci pa_assert(p); 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci s = pa_msgobject_new(upload_stream); 15453a5a1b3Sopenharmony_ci s->parent.parent.parent.free = upload_stream_free; 15553a5a1b3Sopenharmony_ci s->connection = c; 15653a5a1b3Sopenharmony_ci s->sample_spec = *ss; 15753a5a1b3Sopenharmony_ci s->channel_map = *map; 15853a5a1b3Sopenharmony_ci s->name = pa_xstrdup(name); 15953a5a1b3Sopenharmony_ci pa_memchunk_reset(&s->memchunk); 16053a5a1b3Sopenharmony_ci s->length = length; 16153a5a1b3Sopenharmony_ci s->proplist = pa_proplist_copy(p); 16253a5a1b3Sopenharmony_ci pa_proplist_update(s->proplist, PA_UPDATE_MERGE, c->client->proplist); 16353a5a1b3Sopenharmony_ci 16453a5a1b3Sopenharmony_ci pa_idxset_put(c->output_streams, s, &s->index); 16553a5a1b3Sopenharmony_ci 16653a5a1b3Sopenharmony_ci return s; 16753a5a1b3Sopenharmony_ci} 16853a5a1b3Sopenharmony_ci 16953a5a1b3Sopenharmony_ci/* Called from main context */ 17053a5a1b3Sopenharmony_cistatic void record_stream_unlink(record_stream *s) { 17153a5a1b3Sopenharmony_ci pa_assert(s); 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci if (!s->connection) 17453a5a1b3Sopenharmony_ci return; 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci if (s->source_output) { 17753a5a1b3Sopenharmony_ci pa_source_output_unlink(s->source_output); 17853a5a1b3Sopenharmony_ci pa_source_output_unref(s->source_output); 17953a5a1b3Sopenharmony_ci s->source_output = NULL; 18053a5a1b3Sopenharmony_ci } 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_remove_by_data(s->connection->record_streams, s, NULL) == s); 18353a5a1b3Sopenharmony_ci s->connection = NULL; 18453a5a1b3Sopenharmony_ci record_stream_unref(s); 18553a5a1b3Sopenharmony_ci} 18653a5a1b3Sopenharmony_ci 18753a5a1b3Sopenharmony_ci/* Called from main context */ 18853a5a1b3Sopenharmony_cistatic void record_stream_free(pa_object *o) { 18953a5a1b3Sopenharmony_ci record_stream *s = RECORD_STREAM(o); 19053a5a1b3Sopenharmony_ci pa_assert(s); 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci record_stream_unlink(s); 19353a5a1b3Sopenharmony_ci 19453a5a1b3Sopenharmony_ci pa_memblockq_free(s->memblockq); 19553a5a1b3Sopenharmony_ci pa_xfree(s); 19653a5a1b3Sopenharmony_ci} 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci/* Called from main context */ 19953a5a1b3Sopenharmony_cistatic int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { 20053a5a1b3Sopenharmony_ci record_stream *s = RECORD_STREAM(o); 20153a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci if (!s->connection) 20453a5a1b3Sopenharmony_ci return -1; 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci switch (code) { 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci case RECORD_STREAM_MESSAGE_POST_DATA: 20953a5a1b3Sopenharmony_ci 21053a5a1b3Sopenharmony_ci /* We try to keep up to date with how many bytes are 21153a5a1b3Sopenharmony_ci * currently on the fly */ 21253a5a1b3Sopenharmony_ci pa_atomic_sub(&s->on_the_fly, chunk->length); 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { 21553a5a1b3Sopenharmony_ci/* pa_log_warn("Failed to push data into output queue."); */ 21653a5a1b3Sopenharmony_ci return -1; 21753a5a1b3Sopenharmony_ci } 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci if (!pa_pstream_is_pending(s->connection->pstream)) 22053a5a1b3Sopenharmony_ci native_connection_send_memblock(s->connection); 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci break; 22353a5a1b3Sopenharmony_ci } 22453a5a1b3Sopenharmony_ci 22553a5a1b3Sopenharmony_ci return 0; 22653a5a1b3Sopenharmony_ci} 22753a5a1b3Sopenharmony_ci 22853a5a1b3Sopenharmony_ci/* Called from main context */ 22953a5a1b3Sopenharmony_cistatic void fix_record_buffer_attr_pre(record_stream *s) { 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci size_t frame_size; 23253a5a1b3Sopenharmony_ci pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec; 23353a5a1b3Sopenharmony_ci 23453a5a1b3Sopenharmony_ci pa_assert(s); 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_ci /* This function will be called from the main thread, before as 23753a5a1b3Sopenharmony_ci * well as after the source output has been activated using 23853a5a1b3Sopenharmony_ci * pa_source_output_put()! That means it may not touch any 23953a5a1b3Sopenharmony_ci * ->thread_info data! */ 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci frame_size = pa_frame_size(&s->source_output->sample_spec); 24253a5a1b3Sopenharmony_ci s->buffer_attr = s->buffer_attr_req; 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_ci if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH) 24553a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH; 24653a5a1b3Sopenharmony_ci if (s->buffer_attr.maxlength <= 0) 24753a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = (uint32_t) frame_size; 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci if (s->buffer_attr.fragsize == (uint32_t) -1) 25053a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec); 25153a5a1b3Sopenharmony_ci if (s->buffer_attr.fragsize <= 0) 25253a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (uint32_t) frame_size; 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_ci orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec); 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci if (s->early_requests) { 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci /* In early request mode we need to emulate the classic 25953a5a1b3Sopenharmony_ci * fragment-based playback model. Unfortunately we have no 26053a5a1b3Sopenharmony_ci * mechanism to tell the source how often we want it to send us 26153a5a1b3Sopenharmony_ci * data. The next best thing we can do is to set the source's 26253a5a1b3Sopenharmony_ci * total buffer (i.e. its latency) to the fragment size. That 26353a5a1b3Sopenharmony_ci * way it will have to send data at least that often. */ 26453a5a1b3Sopenharmony_ci 26553a5a1b3Sopenharmony_ci source_usec = fragsize_usec; 26653a5a1b3Sopenharmony_ci 26753a5a1b3Sopenharmony_ci } else if (s->adjust_latency) { 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci /* So, the user asked us to adjust the latency according to 27053a5a1b3Sopenharmony_ci * what the source can provide. We set the source to whatever 27153a5a1b3Sopenharmony_ci * latency it can provide that is closest to what we want, and 27253a5a1b3Sopenharmony_ci * let the client buffer be equally large. This does NOT mean 27353a5a1b3Sopenharmony_ci * that we are doing (2 * fragsize) bytes of buffering, since 27453a5a1b3Sopenharmony_ci * the client-side buffer is only data that is on the way to 27553a5a1b3Sopenharmony_ci * the client. */ 27653a5a1b3Sopenharmony_ci 27753a5a1b3Sopenharmony_ci source_usec = fragsize_usec; 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci } else { 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci /* Ok, the user didn't ask us to adjust the latency, hence we 28253a5a1b3Sopenharmony_ci * don't */ 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci source_usec = (pa_usec_t) -1; 28553a5a1b3Sopenharmony_ci } 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci if (source_usec != (pa_usec_t) -1) 28853a5a1b3Sopenharmony_ci s->configured_source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec); 28953a5a1b3Sopenharmony_ci else 29053a5a1b3Sopenharmony_ci s->configured_source_latency = 0; 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_ci if (s->early_requests) { 29353a5a1b3Sopenharmony_ci 29453a5a1b3Sopenharmony_ci /* Ok, we didn't necessarily get what we were asking for. We 29553a5a1b3Sopenharmony_ci * might still get the proper fragment interval, we just can't 29653a5a1b3Sopenharmony_ci * guarantee it. */ 29753a5a1b3Sopenharmony_ci 29853a5a1b3Sopenharmony_ci if (fragsize_usec != s->configured_source_latency) 29953a5a1b3Sopenharmony_ci pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisfied."); 30053a5a1b3Sopenharmony_ci 30153a5a1b3Sopenharmony_ci } else if (s->adjust_latency) { 30253a5a1b3Sopenharmony_ci 30353a5a1b3Sopenharmony_ci /* We keep the client buffer large enough to transfer one 30453a5a1b3Sopenharmony_ci * hardware-buffer-sized chunk at a time to the client. */ 30553a5a1b3Sopenharmony_ci 30653a5a1b3Sopenharmony_ci fragsize_usec = s->configured_source_latency; 30753a5a1b3Sopenharmony_ci } 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) != 31053a5a1b3Sopenharmony_ci pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec)) 31153a5a1b3Sopenharmony_ci 31253a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec); 31353a5a1b3Sopenharmony_ci 31453a5a1b3Sopenharmony_ci if (s->buffer_attr.fragsize <= 0) 31553a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (uint32_t) frame_size; 31653a5a1b3Sopenharmony_ci} 31753a5a1b3Sopenharmony_ci 31853a5a1b3Sopenharmony_ci/* Called from main context */ 31953a5a1b3Sopenharmony_cistatic void fix_record_buffer_attr_post(record_stream *s) { 32053a5a1b3Sopenharmony_ci size_t base; 32153a5a1b3Sopenharmony_ci 32253a5a1b3Sopenharmony_ci pa_assert(s); 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci /* This function will be called from the main thread, before as 32553a5a1b3Sopenharmony_ci * well as after the source output has been activated using 32653a5a1b3Sopenharmony_ci * pa_source_output_put()! That means it may not touch and 32753a5a1b3Sopenharmony_ci * ->thread_info data! */ 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci base = pa_frame_size(&s->source_output->sample_spec); 33053a5a1b3Sopenharmony_ci 33153a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base; 33253a5a1b3Sopenharmony_ci if (s->buffer_attr.fragsize <= 0) 33353a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = base; 33453a5a1b3Sopenharmony_ci 33553a5a1b3Sopenharmony_ci if (s->buffer_attr.fragsize > s->buffer_attr.maxlength) 33653a5a1b3Sopenharmony_ci s->buffer_attr.fragsize = s->buffer_attr.maxlength; 33753a5a1b3Sopenharmony_ci} 33853a5a1b3Sopenharmony_ci 33953a5a1b3Sopenharmony_ci/* Called from main context */ 34053a5a1b3Sopenharmony_cistatic record_stream* record_stream_new( 34153a5a1b3Sopenharmony_ci pa_native_connection *c, 34253a5a1b3Sopenharmony_ci pa_source *source, 34353a5a1b3Sopenharmony_ci pa_sample_spec *ss, 34453a5a1b3Sopenharmony_ci pa_channel_map *map, 34553a5a1b3Sopenharmony_ci pa_idxset *formats, 34653a5a1b3Sopenharmony_ci pa_buffer_attr *attr, 34753a5a1b3Sopenharmony_ci pa_cvolume *volume, 34853a5a1b3Sopenharmony_ci bool muted, 34953a5a1b3Sopenharmony_ci bool muted_set, 35053a5a1b3Sopenharmony_ci pa_source_output_flags_t flags, 35153a5a1b3Sopenharmony_ci pa_proplist *p, 35253a5a1b3Sopenharmony_ci bool adjust_latency, 35353a5a1b3Sopenharmony_ci bool early_requests, 35453a5a1b3Sopenharmony_ci bool relative_volume, 35553a5a1b3Sopenharmony_ci bool peak_detect, 35653a5a1b3Sopenharmony_ci pa_sink_input *direct_on_input, 35753a5a1b3Sopenharmony_ci int *ret) { 35853a5a1b3Sopenharmony_ci 35953a5a1b3Sopenharmony_ci /* Note: This function takes ownership of the 'formats' param, so we need 36053a5a1b3Sopenharmony_ci * to take extra care to not leak it */ 36153a5a1b3Sopenharmony_ci 36253a5a1b3Sopenharmony_ci record_stream *s; 36353a5a1b3Sopenharmony_ci pa_source_output *source_output = NULL; 36453a5a1b3Sopenharmony_ci pa_source_output_new_data data; 36553a5a1b3Sopenharmony_ci char *memblockq_name; 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci pa_assert(c); 36853a5a1b3Sopenharmony_ci pa_assert(ss); 36953a5a1b3Sopenharmony_ci pa_assert(p); 37053a5a1b3Sopenharmony_ci pa_assert(ret); 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci pa_source_output_new_data_init(&data); 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); 37553a5a1b3Sopenharmony_ci data.driver = __FILE__; 37653a5a1b3Sopenharmony_ci data.module = c->options->module; 37753a5a1b3Sopenharmony_ci data.client = c->client; 37853a5a1b3Sopenharmony_ci if (source) 37953a5a1b3Sopenharmony_ci pa_source_output_new_data_set_source(&data, source, false, true); 38053a5a1b3Sopenharmony_ci if (pa_sample_spec_valid(ss)) 38153a5a1b3Sopenharmony_ci pa_source_output_new_data_set_sample_spec(&data, ss); 38253a5a1b3Sopenharmony_ci if (pa_channel_map_valid(map)) 38353a5a1b3Sopenharmony_ci pa_source_output_new_data_set_channel_map(&data, map); 38453a5a1b3Sopenharmony_ci if (formats) 38553a5a1b3Sopenharmony_ci pa_source_output_new_data_set_formats(&data, formats); 38653a5a1b3Sopenharmony_ci data.direct_on_input = direct_on_input; 38753a5a1b3Sopenharmony_ci if (volume) { 38853a5a1b3Sopenharmony_ci pa_source_output_new_data_set_volume(&data, volume); 38953a5a1b3Sopenharmony_ci data.volume_is_absolute = !relative_volume; 39053a5a1b3Sopenharmony_ci data.save_volume = false; 39153a5a1b3Sopenharmony_ci } 39253a5a1b3Sopenharmony_ci if (muted_set) { 39353a5a1b3Sopenharmony_ci pa_source_output_new_data_set_muted(&data, muted); 39453a5a1b3Sopenharmony_ci data.save_muted = false; 39553a5a1b3Sopenharmony_ci } 39653a5a1b3Sopenharmony_ci if (peak_detect) 39753a5a1b3Sopenharmony_ci data.resample_method = PA_RESAMPLER_PEAKS; 39853a5a1b3Sopenharmony_ci data.flags = flags; 39953a5a1b3Sopenharmony_ci 40053a5a1b3Sopenharmony_ci *ret = -pa_source_output_new(&source_output, c->protocol->core, &data); 40153a5a1b3Sopenharmony_ci 40253a5a1b3Sopenharmony_ci pa_source_output_new_data_done(&data); 40353a5a1b3Sopenharmony_ci 40453a5a1b3Sopenharmony_ci if (!source_output) 40553a5a1b3Sopenharmony_ci return NULL; 40653a5a1b3Sopenharmony_ci 40753a5a1b3Sopenharmony_ci s = pa_msgobject_new(record_stream); 40853a5a1b3Sopenharmony_ci s->parent.parent.free = record_stream_free; 40953a5a1b3Sopenharmony_ci s->parent.process_msg = record_stream_process_msg; 41053a5a1b3Sopenharmony_ci s->connection = c; 41153a5a1b3Sopenharmony_ci s->source_output = source_output; 41253a5a1b3Sopenharmony_ci s->buffer_attr_req = *attr; 41353a5a1b3Sopenharmony_ci s->adjust_latency = adjust_latency; 41453a5a1b3Sopenharmony_ci s->early_requests = early_requests; 41553a5a1b3Sopenharmony_ci pa_atomic_store(&s->on_the_fly, 0); 41653a5a1b3Sopenharmony_ci 41753a5a1b3Sopenharmony_ci s->source_output->parent.process_msg = source_output_process_msg; 41853a5a1b3Sopenharmony_ci s->source_output->push = source_output_push_cb; 41953a5a1b3Sopenharmony_ci s->source_output->kill = source_output_kill_cb; 42053a5a1b3Sopenharmony_ci s->source_output->get_latency = source_output_get_latency_cb; 42153a5a1b3Sopenharmony_ci s->source_output->moving = source_output_moving_cb; 42253a5a1b3Sopenharmony_ci s->source_output->suspend = source_output_suspend_cb; 42353a5a1b3Sopenharmony_ci s->source_output->send_event = source_output_send_event_cb; 42453a5a1b3Sopenharmony_ci s->source_output->userdata = s; 42553a5a1b3Sopenharmony_ci 42653a5a1b3Sopenharmony_ci fix_record_buffer_attr_pre(s); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci memblockq_name = pa_sprintf_malloc("native protocol record stream memblockq [%u]", s->source_output->index); 42953a5a1b3Sopenharmony_ci s->memblockq = pa_memblockq_new( 43053a5a1b3Sopenharmony_ci memblockq_name, 43153a5a1b3Sopenharmony_ci 0, 43253a5a1b3Sopenharmony_ci s->buffer_attr.maxlength, 43353a5a1b3Sopenharmony_ci 0, 43453a5a1b3Sopenharmony_ci &source_output->sample_spec, 43553a5a1b3Sopenharmony_ci 1, 43653a5a1b3Sopenharmony_ci 0, 43753a5a1b3Sopenharmony_ci 0, 43853a5a1b3Sopenharmony_ci NULL); 43953a5a1b3Sopenharmony_ci pa_xfree(memblockq_name); 44053a5a1b3Sopenharmony_ci 44153a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 44253a5a1b3Sopenharmony_ci fix_record_buffer_attr_post(s); 44353a5a1b3Sopenharmony_ci 44453a5a1b3Sopenharmony_ci *ss = s->source_output->sample_spec; 44553a5a1b3Sopenharmony_ci *map = s->source_output->channel_map; 44653a5a1b3Sopenharmony_ci 44753a5a1b3Sopenharmony_ci pa_idxset_put(c->record_streams, s, &s->index); 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci pa_log_debug("Final latency %0.2f ms = %0.2f ms + %0.2f ms", 45053a5a1b3Sopenharmony_ci ((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->configured_source_latency) / PA_USEC_PER_MSEC, 45153a5a1b3Sopenharmony_ci (double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC, 45253a5a1b3Sopenharmony_ci (double) s->configured_source_latency / PA_USEC_PER_MSEC); 45353a5a1b3Sopenharmony_ci 45453a5a1b3Sopenharmony_ci pa_source_output_put(s->source_output); 45553a5a1b3Sopenharmony_ci return s; 45653a5a1b3Sopenharmony_ci} 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci/* Called from main context */ 45953a5a1b3Sopenharmony_cistatic void record_stream_send_killed(record_stream *r) { 46053a5a1b3Sopenharmony_ci pa_tagstruct *t; 46153a5a1b3Sopenharmony_ci record_stream_assert_ref(r); 46253a5a1b3Sopenharmony_ci 46353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 46453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_KILLED); 46553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 46653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, r->index); 46753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(r->connection->pstream, t); 46853a5a1b3Sopenharmony_ci} 46953a5a1b3Sopenharmony_ci 47053a5a1b3Sopenharmony_ci/* Called from main context */ 47153a5a1b3Sopenharmony_cistatic void playback_stream_unlink(playback_stream *s) { 47253a5a1b3Sopenharmony_ci pa_assert(s); 47353a5a1b3Sopenharmony_ci 47453a5a1b3Sopenharmony_ci if (!s->connection) 47553a5a1b3Sopenharmony_ci return; 47653a5a1b3Sopenharmony_ci 47753a5a1b3Sopenharmony_ci if (s->sink_input) { 47853a5a1b3Sopenharmony_ci pa_sink_input_unlink(s->sink_input); 47953a5a1b3Sopenharmony_ci pa_sink_input_unref(s->sink_input); 48053a5a1b3Sopenharmony_ci s->sink_input = NULL; 48153a5a1b3Sopenharmony_ci } 48253a5a1b3Sopenharmony_ci 48353a5a1b3Sopenharmony_ci if (s->drain_request) 48453a5a1b3Sopenharmony_ci pa_pstream_send_error(s->connection->pstream, s->drain_tag, PA_ERR_NOENTITY); 48553a5a1b3Sopenharmony_ci 48653a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_remove_by_data(s->connection->output_streams, s, NULL) == s); 48753a5a1b3Sopenharmony_ci s->connection = NULL; 48853a5a1b3Sopenharmony_ci playback_stream_unref(s); 48953a5a1b3Sopenharmony_ci} 49053a5a1b3Sopenharmony_ci 49153a5a1b3Sopenharmony_ci/* Called from main context */ 49253a5a1b3Sopenharmony_cistatic void playback_stream_free(pa_object* o) { 49353a5a1b3Sopenharmony_ci playback_stream *s = PLAYBACK_STREAM(o); 49453a5a1b3Sopenharmony_ci pa_assert(s); 49553a5a1b3Sopenharmony_ci 49653a5a1b3Sopenharmony_ci playback_stream_unlink(s); 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci pa_memblockq_free(s->memblockq); 49953a5a1b3Sopenharmony_ci pa_xfree(s); 50053a5a1b3Sopenharmony_ci} 50153a5a1b3Sopenharmony_ci 50253a5a1b3Sopenharmony_ci/* Called from main context */ 50353a5a1b3Sopenharmony_cistatic int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { 50453a5a1b3Sopenharmony_ci playback_stream *s = PLAYBACK_STREAM(o); 50553a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 50653a5a1b3Sopenharmony_ci 50753a5a1b3Sopenharmony_ci if (!s->connection) 50853a5a1b3Sopenharmony_ci return -1; 50953a5a1b3Sopenharmony_ci 51053a5a1b3Sopenharmony_ci switch (code) { 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA: { 51353a5a1b3Sopenharmony_ci pa_tagstruct *t; 51453a5a1b3Sopenharmony_ci int l = 0; 51553a5a1b3Sopenharmony_ci 51653a5a1b3Sopenharmony_ci for (;;) { 51753a5a1b3Sopenharmony_ci if ((l = pa_atomic_load(&s->missing)) <= 0) 51853a5a1b3Sopenharmony_ci return 0; 51953a5a1b3Sopenharmony_ci 52053a5a1b3Sopenharmony_ci if (pa_atomic_cmpxchg(&s->missing, l, 0)) 52153a5a1b3Sopenharmony_ci break; 52253a5a1b3Sopenharmony_ci } 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 52553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_REQUEST); 52653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 52753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 52853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) l); 52953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 53053a5a1b3Sopenharmony_ci 53153a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 53253a5a1b3Sopenharmony_ci pa_log("Requesting %lu bytes", (unsigned long) l); 53353a5a1b3Sopenharmony_ci#endif 53453a5a1b3Sopenharmony_ci break; 53553a5a1b3Sopenharmony_ci } 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: { 53853a5a1b3Sopenharmony_ci pa_tagstruct *t; 53953a5a1b3Sopenharmony_ci 54053a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 54153a5a1b3Sopenharmony_ci pa_log("signalling underflow"); 54253a5a1b3Sopenharmony_ci#endif 54353a5a1b3Sopenharmony_ci 54453a5a1b3Sopenharmony_ci /* Report that we're empty */ 54553a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 54653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); 54753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 54853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 54953a5a1b3Sopenharmony_ci if (s->connection->version >= 23) 55053a5a1b3Sopenharmony_ci pa_tagstruct_puts64(t, offset); 55153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 55253a5a1b3Sopenharmony_ci break; 55353a5a1b3Sopenharmony_ci } 55453a5a1b3Sopenharmony_ci 55553a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_OVERFLOW: { 55653a5a1b3Sopenharmony_ci pa_tagstruct *t; 55753a5a1b3Sopenharmony_ci 55853a5a1b3Sopenharmony_ci /* Notify the user we're overflowed*/ 55953a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 56053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_OVERFLOW); 56153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 56253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 56353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 56453a5a1b3Sopenharmony_ci break; 56553a5a1b3Sopenharmony_ci } 56653a5a1b3Sopenharmony_ci 56753a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_STARTED: 56853a5a1b3Sopenharmony_ci 56953a5a1b3Sopenharmony_ci if (s->connection->version >= 13) { 57053a5a1b3Sopenharmony_ci pa_tagstruct *t; 57153a5a1b3Sopenharmony_ci 57253a5a1b3Sopenharmony_ci /* Notify the user we started playback */ 57353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 57453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_STARTED); 57553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 57653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 57753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 57853a5a1b3Sopenharmony_ci } 57953a5a1b3Sopenharmony_ci 58053a5a1b3Sopenharmony_ci break; 58153a5a1b3Sopenharmony_ci 58253a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK: 58353a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata)); 58453a5a1b3Sopenharmony_ci break; 58553a5a1b3Sopenharmony_ci 58653a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: 58753a5a1b3Sopenharmony_ci 58853a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) offset; 58953a5a1b3Sopenharmony_ci 59053a5a1b3Sopenharmony_ci if (s->connection->version >= 15) { 59153a5a1b3Sopenharmony_ci pa_tagstruct *t; 59253a5a1b3Sopenharmony_ci 59353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 59453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED); 59553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 59653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 59753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.maxlength); 59853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.tlength); 59953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.prebuf); 60053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.minreq); 60153a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, s->configured_sink_latency); 60253a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 60353a5a1b3Sopenharmony_ci } 60453a5a1b3Sopenharmony_ci 60553a5a1b3Sopenharmony_ci case PLAYBACK_STREAM_MESSAGE_UNDERFLOW_OHOS: { 60653a5a1b3Sopenharmony_ci pa_tagstruct *t; 60753a5a1b3Sopenharmony_ci 60853a5a1b3Sopenharmony_ci /* Notify the user we're overflowed*/ 60953a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 61053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW_OHOS); 61153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 61253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 61353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 61453a5a1b3Sopenharmony_ci break; 61553a5a1b3Sopenharmony_ci } 61653a5a1b3Sopenharmony_ci 61753a5a1b3Sopenharmony_ci break; 61853a5a1b3Sopenharmony_ci } 61953a5a1b3Sopenharmony_ci 62053a5a1b3Sopenharmony_ci return 0; 62153a5a1b3Sopenharmony_ci} 62253a5a1b3Sopenharmony_ci 62353a5a1b3Sopenharmony_ci/* Called from main context */ 62453a5a1b3Sopenharmony_cistatic void fix_playback_buffer_attr(playback_stream *s) { 62553a5a1b3Sopenharmony_ci size_t frame_size, max_prebuf; 62653a5a1b3Sopenharmony_ci pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec; 62753a5a1b3Sopenharmony_ci 62853a5a1b3Sopenharmony_ci pa_assert(s); 62953a5a1b3Sopenharmony_ci 63053a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 63153a5a1b3Sopenharmony_ci pa_log_debug("Client requested: maxlength=%li bytes tlength=%li bytes minreq=%li bytes prebuf=%li bytes", 63253a5a1b3Sopenharmony_ci (long) s->buffer_attr_req.maxlength, 63353a5a1b3Sopenharmony_ci (long) s->buffer_attr_req.tlength, 63453a5a1b3Sopenharmony_ci (long) s->buffer_attr_req.minreq, 63553a5a1b3Sopenharmony_ci (long) s->buffer_attr_req.prebuf); 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci pa_log("Client requested: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", 63853a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 63953a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 64053a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 64153a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr_req.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); 64253a5a1b3Sopenharmony_ci#endif 64353a5a1b3Sopenharmony_ci 64453a5a1b3Sopenharmony_ci /* This function will be called from the main thread, before as 64553a5a1b3Sopenharmony_ci * well as after the sink input has been activated using 64653a5a1b3Sopenharmony_ci * pa_sink_input_put()! That means it may not touch any 64753a5a1b3Sopenharmony_ci * ->thread_info data, such as the memblockq! */ 64853a5a1b3Sopenharmony_ci 64953a5a1b3Sopenharmony_ci frame_size = pa_frame_size(&s->sink_input->sample_spec); 65053a5a1b3Sopenharmony_ci s->buffer_attr = s->buffer_attr_req; 65153a5a1b3Sopenharmony_ci 65253a5a1b3Sopenharmony_ci if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH) 65353a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH; 65453a5a1b3Sopenharmony_ci if (s->buffer_attr.maxlength <= 0) 65553a5a1b3Sopenharmony_ci s->buffer_attr.maxlength = (uint32_t) frame_size; 65653a5a1b3Sopenharmony_ci 65753a5a1b3Sopenharmony_ci if (s->buffer_attr.tlength == (uint32_t) -1) 65853a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); 65953a5a1b3Sopenharmony_ci if (s->buffer_attr.tlength <= 0) 66053a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) frame_size; 66153a5a1b3Sopenharmony_ci if (s->buffer_attr.tlength > s->buffer_attr.maxlength) 66253a5a1b3Sopenharmony_ci s->buffer_attr.tlength = s->buffer_attr.maxlength; 66353a5a1b3Sopenharmony_ci 66453a5a1b3Sopenharmony_ci if (s->buffer_attr.minreq == (uint32_t) -1) { 66553a5a1b3Sopenharmony_ci uint32_t process = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); 66653a5a1b3Sopenharmony_ci /* With low-latency, tlength/4 gives a decent default in all of traditional, adjust latency and early request modes. */ 66753a5a1b3Sopenharmony_ci uint32_t m = s->buffer_attr.tlength / 4; 66853a5a1b3Sopenharmony_ci if (frame_size) 66953a5a1b3Sopenharmony_ci m -= m % frame_size; 67053a5a1b3Sopenharmony_ci s->buffer_attr.minreq = PA_MIN(process, m); 67153a5a1b3Sopenharmony_ci } 67253a5a1b3Sopenharmony_ci if (s->buffer_attr.minreq <= 0) 67353a5a1b3Sopenharmony_ci s->buffer_attr.minreq = (uint32_t) frame_size; 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_ci if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size) 67653a5a1b3Sopenharmony_ci s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size; 67753a5a1b3Sopenharmony_ci 67853a5a1b3Sopenharmony_ci orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec); 67953a5a1b3Sopenharmony_ci orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec); 68053a5a1b3Sopenharmony_ci 68153a5a1b3Sopenharmony_ci pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms", 68253a5a1b3Sopenharmony_ci (double) tlength_usec / PA_USEC_PER_MSEC, 68353a5a1b3Sopenharmony_ci (double) minreq_usec / PA_USEC_PER_MSEC); 68453a5a1b3Sopenharmony_ci 68553a5a1b3Sopenharmony_ci if (s->early_requests) { 68653a5a1b3Sopenharmony_ci 68753a5a1b3Sopenharmony_ci /* In early request mode we need to emulate the classic 68853a5a1b3Sopenharmony_ci * fragment-based playback model. Unfortunately we have no 68953a5a1b3Sopenharmony_ci * mechanism to tell the sink how often we want to be queried 69053a5a1b3Sopenharmony_ci * for data. The next best thing we can do is to set the sink's 69153a5a1b3Sopenharmony_ci * total buffer (i.e. its latency) to the fragment size. That 69253a5a1b3Sopenharmony_ci * way it will have to query us at least that often. */ 69353a5a1b3Sopenharmony_ci 69453a5a1b3Sopenharmony_ci sink_usec = minreq_usec; 69553a5a1b3Sopenharmony_ci pa_log_debug("Early requests mode enabled, configuring sink latency to minreq."); 69653a5a1b3Sopenharmony_ci 69753a5a1b3Sopenharmony_ci } else if (s->adjust_latency) { 69853a5a1b3Sopenharmony_ci 69953a5a1b3Sopenharmony_ci /* So, the user asked us to adjust the latency of the stream 70053a5a1b3Sopenharmony_ci * buffer according to the what the sink can provide. The 70153a5a1b3Sopenharmony_ci * tlength passed in shall be the overall latency. Roughly 70253a5a1b3Sopenharmony_ci * half the latency will be spent on the hw buffer, the other 70353a5a1b3Sopenharmony_ci * half of it in the async buffer queue we maintain for each 70453a5a1b3Sopenharmony_ci * client. In between we'll have a safety space of size 70553a5a1b3Sopenharmony_ci * 2*minreq. Why the 2*minreq? When the hw buffer is completely 70653a5a1b3Sopenharmony_ci * empty and needs to be filled, then our buffer must have 70753a5a1b3Sopenharmony_ci * enough data to fulfill this request immediately and thus 70853a5a1b3Sopenharmony_ci * have at least the same tlength as the size of the hw 70953a5a1b3Sopenharmony_ci * buffer. It additionally needs space for 2 times minreq 71053a5a1b3Sopenharmony_ci * because if the buffer ran empty and a partial fillup 71153a5a1b3Sopenharmony_ci * happens immediately on the next iteration we need to be 71253a5a1b3Sopenharmony_ci * able to fulfill it and give the application also minreq 71353a5a1b3Sopenharmony_ci * time to fill it up again for the next request Makes 2 times 71453a5a1b3Sopenharmony_ci * minreq in plus.. */ 71553a5a1b3Sopenharmony_ci 71653a5a1b3Sopenharmony_ci if (tlength_usec > minreq_usec*2) 71753a5a1b3Sopenharmony_ci sink_usec = (tlength_usec - minreq_usec*2)/2; 71853a5a1b3Sopenharmony_ci else 71953a5a1b3Sopenharmony_ci sink_usec = 0; 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency."); 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ci } else { 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci /* Ok, the user didn't ask us to adjust the latency, but we 72653a5a1b3Sopenharmony_ci * still need to make sure that the parameters from the user 72753a5a1b3Sopenharmony_ci * do make sense. */ 72853a5a1b3Sopenharmony_ci 72953a5a1b3Sopenharmony_ci if (tlength_usec > minreq_usec*2) 73053a5a1b3Sopenharmony_ci sink_usec = (tlength_usec - minreq_usec*2); 73153a5a1b3Sopenharmony_ci else 73253a5a1b3Sopenharmony_ci sink_usec = 0; 73353a5a1b3Sopenharmony_ci 73453a5a1b3Sopenharmony_ci pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq."); 73553a5a1b3Sopenharmony_ci } 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_ci s->configured_sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec); 73853a5a1b3Sopenharmony_ci 73953a5a1b3Sopenharmony_ci if (s->early_requests) { 74053a5a1b3Sopenharmony_ci 74153a5a1b3Sopenharmony_ci /* Ok, we didn't necessarily get what we were asking for. We 74253a5a1b3Sopenharmony_ci * might still get the proper fragment interval, we just can't 74353a5a1b3Sopenharmony_ci * guarantee it. */ 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_ci if (minreq_usec != s->configured_sink_latency) 74653a5a1b3Sopenharmony_ci pa_log_debug("Could not configure a sufficiently low latency. Early requests might not be satisfied."); 74753a5a1b3Sopenharmony_ci 74853a5a1b3Sopenharmony_ci } else if (s->adjust_latency) { 74953a5a1b3Sopenharmony_ci 75053a5a1b3Sopenharmony_ci /* Ok, we didn't necessarily get what we were asking for, so 75153a5a1b3Sopenharmony_ci * let's subtract from what we asked for for the remaining 75253a5a1b3Sopenharmony_ci * buffer space */ 75353a5a1b3Sopenharmony_ci 75453a5a1b3Sopenharmony_ci if (tlength_usec >= s->configured_sink_latency) 75553a5a1b3Sopenharmony_ci tlength_usec -= s->configured_sink_latency; 75653a5a1b3Sopenharmony_ci } 75753a5a1b3Sopenharmony_ci 75853a5a1b3Sopenharmony_ci pa_log_debug("Requested latency=%0.2f ms, Received latency=%0.2f ms", 75953a5a1b3Sopenharmony_ci (double) sink_usec / PA_USEC_PER_MSEC, 76053a5a1b3Sopenharmony_ci (double) s->configured_sink_latency / PA_USEC_PER_MSEC); 76153a5a1b3Sopenharmony_ci 76253a5a1b3Sopenharmony_ci /* FIXME: This is actually larger than necessary, since not all of 76353a5a1b3Sopenharmony_ci * the sink latency is actually rewritable. */ 76453a5a1b3Sopenharmony_ci if (tlength_usec < s->configured_sink_latency + 2*minreq_usec) 76553a5a1b3Sopenharmony_ci tlength_usec = s->configured_sink_latency + 2*minreq_usec; 76653a5a1b3Sopenharmony_ci 76753a5a1b3Sopenharmony_ci if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) != 76853a5a1b3Sopenharmony_ci pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec)) 76953a5a1b3Sopenharmony_ci s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec); 77053a5a1b3Sopenharmony_ci 77153a5a1b3Sopenharmony_ci if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) != 77253a5a1b3Sopenharmony_ci pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec)) 77353a5a1b3Sopenharmony_ci s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec); 77453a5a1b3Sopenharmony_ci 77553a5a1b3Sopenharmony_ci if (s->buffer_attr.minreq <= 0) { 77653a5a1b3Sopenharmony_ci s->buffer_attr.minreq = (uint32_t) frame_size; 77753a5a1b3Sopenharmony_ci s->buffer_attr.tlength += (uint32_t) frame_size*2; 77853a5a1b3Sopenharmony_ci } 77953a5a1b3Sopenharmony_ci 78053a5a1b3Sopenharmony_ci if (s->buffer_attr.tlength <= s->buffer_attr.minreq) 78153a5a1b3Sopenharmony_ci s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size; 78253a5a1b3Sopenharmony_ci 78353a5a1b3Sopenharmony_ci max_prebuf = s->buffer_attr.tlength + (uint32_t)frame_size - s->buffer_attr.minreq; 78453a5a1b3Sopenharmony_ci 78553a5a1b3Sopenharmony_ci if (s->buffer_attr.prebuf == (uint32_t) -1 || 78653a5a1b3Sopenharmony_ci s->buffer_attr.prebuf > max_prebuf) 78753a5a1b3Sopenharmony_ci s->buffer_attr.prebuf = max_prebuf; 78853a5a1b3Sopenharmony_ci 78953a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 79053a5a1b3Sopenharmony_ci pa_log("Client accepted: maxlength=%lu ms tlength=%lu ms minreq=%lu ms prebuf=%lu ms", 79153a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr.maxlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 79253a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 79353a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC), 79453a5a1b3Sopenharmony_ci (unsigned long) (pa_bytes_to_usec(s->buffer_attr.prebuf, &s->sink_input->sample_spec) / PA_USEC_PER_MSEC)); 79553a5a1b3Sopenharmony_ci#endif 79653a5a1b3Sopenharmony_ci} 79753a5a1b3Sopenharmony_ci 79853a5a1b3Sopenharmony_ci/* Called from main context */ 79953a5a1b3Sopenharmony_cistatic playback_stream* playback_stream_new( 80053a5a1b3Sopenharmony_ci pa_native_connection *c, 80153a5a1b3Sopenharmony_ci pa_sink *sink, 80253a5a1b3Sopenharmony_ci pa_sample_spec *ss, 80353a5a1b3Sopenharmony_ci pa_channel_map *map, 80453a5a1b3Sopenharmony_ci pa_idxset *formats, 80553a5a1b3Sopenharmony_ci pa_buffer_attr *a, 80653a5a1b3Sopenharmony_ci pa_cvolume *volume, 80753a5a1b3Sopenharmony_ci bool muted, 80853a5a1b3Sopenharmony_ci bool muted_set, 80953a5a1b3Sopenharmony_ci pa_sink_input_flags_t flags, 81053a5a1b3Sopenharmony_ci pa_proplist *p, 81153a5a1b3Sopenharmony_ci bool adjust_latency, 81253a5a1b3Sopenharmony_ci bool early_requests, 81353a5a1b3Sopenharmony_ci bool relative_volume, 81453a5a1b3Sopenharmony_ci uint32_t syncid, 81553a5a1b3Sopenharmony_ci uint32_t *missing, 81653a5a1b3Sopenharmony_ci int *ret) { 81753a5a1b3Sopenharmony_ci 81853a5a1b3Sopenharmony_ci /* Note: This function takes ownership of the 'formats' param, so we need 81953a5a1b3Sopenharmony_ci * to take extra care to not leak it */ 82053a5a1b3Sopenharmony_ci 82153a5a1b3Sopenharmony_ci playback_stream *ssync; 82253a5a1b3Sopenharmony_ci playback_stream *s = NULL; 82353a5a1b3Sopenharmony_ci pa_sink_input *sink_input = NULL; 82453a5a1b3Sopenharmony_ci pa_memchunk silence; 82553a5a1b3Sopenharmony_ci uint32_t idx; 82653a5a1b3Sopenharmony_ci int64_t start_index; 82753a5a1b3Sopenharmony_ci pa_sink_input_new_data data; 82853a5a1b3Sopenharmony_ci char *memblockq_name; 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci pa_assert(c); 83153a5a1b3Sopenharmony_ci pa_assert(ss); 83253a5a1b3Sopenharmony_ci pa_assert(missing); 83353a5a1b3Sopenharmony_ci pa_assert(p); 83453a5a1b3Sopenharmony_ci pa_assert(ret); 83553a5a1b3Sopenharmony_ci 83653a5a1b3Sopenharmony_ci /* Find syncid group */ 83753a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(ssync, c->output_streams, idx) { 83853a5a1b3Sopenharmony_ci 83953a5a1b3Sopenharmony_ci if (!playback_stream_isinstance(ssync)) 84053a5a1b3Sopenharmony_ci continue; 84153a5a1b3Sopenharmony_ci 84253a5a1b3Sopenharmony_ci if (ssync->syncid == syncid) 84353a5a1b3Sopenharmony_ci break; 84453a5a1b3Sopenharmony_ci } 84553a5a1b3Sopenharmony_ci 84653a5a1b3Sopenharmony_ci /* Synced streams must connect to the same sink */ 84753a5a1b3Sopenharmony_ci if (ssync) { 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci if (!sink) 85053a5a1b3Sopenharmony_ci sink = ssync->sink_input->sink; 85153a5a1b3Sopenharmony_ci else if (sink != ssync->sink_input->sink) { 85253a5a1b3Sopenharmony_ci *ret = PA_ERR_INVALID; 85353a5a1b3Sopenharmony_ci goto out; 85453a5a1b3Sopenharmony_ci } 85553a5a1b3Sopenharmony_ci } 85653a5a1b3Sopenharmony_ci 85753a5a1b3Sopenharmony_ci pa_sink_input_new_data_init(&data); 85853a5a1b3Sopenharmony_ci 85953a5a1b3Sopenharmony_ci pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); 86053a5a1b3Sopenharmony_ci data.driver = __FILE__; 86153a5a1b3Sopenharmony_ci data.module = c->options->module; 86253a5a1b3Sopenharmony_ci data.client = c->client; 86353a5a1b3Sopenharmony_ci if (sink) 86453a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sink(&data, sink, false, true); 86553a5a1b3Sopenharmony_ci if (pa_sample_spec_valid(ss)) 86653a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_sample_spec(&data, ss); 86753a5a1b3Sopenharmony_ci if (pa_channel_map_valid(map)) 86853a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_channel_map(&data, map); 86953a5a1b3Sopenharmony_ci if (formats) { 87053a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_formats(&data, formats); 87153a5a1b3Sopenharmony_ci /* Ownership transferred to new_data, so we don't free it ourselves */ 87253a5a1b3Sopenharmony_ci formats = NULL; 87353a5a1b3Sopenharmony_ci } 87453a5a1b3Sopenharmony_ci if (volume) { 87553a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_volume(&data, volume); 87653a5a1b3Sopenharmony_ci data.volume_is_absolute = !relative_volume; 87753a5a1b3Sopenharmony_ci data.save_volume = false; 87853a5a1b3Sopenharmony_ci } 87953a5a1b3Sopenharmony_ci if (muted_set) { 88053a5a1b3Sopenharmony_ci pa_sink_input_new_data_set_muted(&data, muted); 88153a5a1b3Sopenharmony_ci data.save_muted = false; 88253a5a1b3Sopenharmony_ci } 88353a5a1b3Sopenharmony_ci data.sync_base = ssync ? ssync->sink_input : NULL; 88453a5a1b3Sopenharmony_ci data.flags = flags; 88553a5a1b3Sopenharmony_ci 88653a5a1b3Sopenharmony_ci *ret = -pa_sink_input_new(&sink_input, c->protocol->core, &data); 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_ci pa_sink_input_new_data_done(&data); 88953a5a1b3Sopenharmony_ci 89053a5a1b3Sopenharmony_ci if (!sink_input) 89153a5a1b3Sopenharmony_ci goto out; 89253a5a1b3Sopenharmony_ci 89353a5a1b3Sopenharmony_ci s = pa_msgobject_new(playback_stream); 89453a5a1b3Sopenharmony_ci s->parent.parent.parent.free = playback_stream_free; 89553a5a1b3Sopenharmony_ci s->parent.parent.process_msg = playback_stream_process_msg; 89653a5a1b3Sopenharmony_ci s->connection = c; 89753a5a1b3Sopenharmony_ci s->syncid = syncid; 89853a5a1b3Sopenharmony_ci s->sink_input = sink_input; 89953a5a1b3Sopenharmony_ci s->is_underrun = true; 90053a5a1b3Sopenharmony_ci s->drain_request = false; 90153a5a1b3Sopenharmony_ci pa_atomic_store(&s->missing, 0); 90253a5a1b3Sopenharmony_ci s->buffer_attr_req = *a; 90353a5a1b3Sopenharmony_ci s->adjust_latency = adjust_latency; 90453a5a1b3Sopenharmony_ci s->early_requests = early_requests; 90553a5a1b3Sopenharmony_ci pa_atomic_store(&s->seek_or_post_in_queue, 0); 90653a5a1b3Sopenharmony_ci s->seek_windex = -1; 90753a5a1b3Sopenharmony_ci 90853a5a1b3Sopenharmony_ci s->sink_input->parent.process_msg = sink_input_process_msg; 90953a5a1b3Sopenharmony_ci s->sink_input->pop = sink_input_pop_cb; 91053a5a1b3Sopenharmony_ci s->sink_input->process_underrun = sink_input_process_underrun_cb; 91153a5a1b3Sopenharmony_ci s->sink_input->process_rewind = sink_input_process_rewind_cb; 91253a5a1b3Sopenharmony_ci s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; 91353a5a1b3Sopenharmony_ci s->sink_input->update_max_request = sink_input_update_max_request_cb; 91453a5a1b3Sopenharmony_ci s->sink_input->kill = sink_input_kill_cb; 91553a5a1b3Sopenharmony_ci s->sink_input->moving = sink_input_moving_cb; 91653a5a1b3Sopenharmony_ci s->sink_input->suspend = sink_input_suspend_cb; 91753a5a1b3Sopenharmony_ci s->sink_input->send_event = sink_input_send_event_cb; 91853a5a1b3Sopenharmony_ci s->sink_input->userdata = s; 91953a5a1b3Sopenharmony_ci 92053a5a1b3Sopenharmony_ci s->sink_input->process_underrun_ohos = sink_input_process_underrun_ohos_cb; 92153a5a1b3Sopenharmony_ci 92253a5a1b3Sopenharmony_ci start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; 92353a5a1b3Sopenharmony_ci 92453a5a1b3Sopenharmony_ci fix_playback_buffer_attr(s); 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_ci pa_sink_input_get_silence(sink_input, &silence); 92753a5a1b3Sopenharmony_ci memblockq_name = pa_sprintf_malloc("native protocol playback stream memblockq [%u]", s->sink_input->index); 92853a5a1b3Sopenharmony_ci s->memblockq = pa_memblockq_new( 92953a5a1b3Sopenharmony_ci memblockq_name, 93053a5a1b3Sopenharmony_ci start_index, 93153a5a1b3Sopenharmony_ci s->buffer_attr.maxlength, 93253a5a1b3Sopenharmony_ci s->buffer_attr.tlength, 93353a5a1b3Sopenharmony_ci &sink_input->sample_spec, 93453a5a1b3Sopenharmony_ci s->buffer_attr.prebuf, 93553a5a1b3Sopenharmony_ci s->buffer_attr.minreq, 93653a5a1b3Sopenharmony_ci 0, 93753a5a1b3Sopenharmony_ci &silence); 93853a5a1b3Sopenharmony_ci pa_xfree(memblockq_name); 93953a5a1b3Sopenharmony_ci pa_memblock_unref(silence.memblock); 94053a5a1b3Sopenharmony_ci 94153a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 94253a5a1b3Sopenharmony_ci 94353a5a1b3Sopenharmony_ci *missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq); 94453a5a1b3Sopenharmony_ci 94553a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 94653a5a1b3Sopenharmony_ci pa_log("missing original: %li", (long int) *missing); 94753a5a1b3Sopenharmony_ci#endif 94853a5a1b3Sopenharmony_ci 94953a5a1b3Sopenharmony_ci *ss = s->sink_input->sample_spec; 95053a5a1b3Sopenharmony_ci *map = s->sink_input->channel_map; 95153a5a1b3Sopenharmony_ci 95253a5a1b3Sopenharmony_ci pa_idxset_put(c->output_streams, s, &s->index); 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci pa_log_debug("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms", 95553a5a1b3Sopenharmony_ci ((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->configured_sink_latency) / PA_USEC_PER_MSEC, 95653a5a1b3Sopenharmony_ci (double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC, 95753a5a1b3Sopenharmony_ci (double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC, 95853a5a1b3Sopenharmony_ci (double) s->configured_sink_latency / PA_USEC_PER_MSEC); 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci pa_sink_input_put(s->sink_input); 96153a5a1b3Sopenharmony_ci 96253a5a1b3Sopenharmony_ciout: 96353a5a1b3Sopenharmony_ci if (formats) 96453a5a1b3Sopenharmony_ci pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free); 96553a5a1b3Sopenharmony_ci 96653a5a1b3Sopenharmony_ci return s; 96753a5a1b3Sopenharmony_ci} 96853a5a1b3Sopenharmony_ci 96953a5a1b3Sopenharmony_ci/* Called from main context */ 97053a5a1b3Sopenharmony_cistatic void playback_stream_send_killed(playback_stream *p) { 97153a5a1b3Sopenharmony_ci pa_tagstruct *t; 97253a5a1b3Sopenharmony_ci playback_stream_assert_ref(p); 97353a5a1b3Sopenharmony_ci 97453a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 97553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_KILLED); 97653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 97753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->index); 97853a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(p->connection->pstream, t); 97953a5a1b3Sopenharmony_ci} 98053a5a1b3Sopenharmony_ci 98153a5a1b3Sopenharmony_ci/* Called from main context */ 98253a5a1b3Sopenharmony_cistatic int native_connection_process_msg(pa_msgobject *o, int code, void*userdata, int64_t offset, pa_memchunk *chunk) { 98353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(o); 98453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 98553a5a1b3Sopenharmony_ci 98653a5a1b3Sopenharmony_ci if (!c->protocol) 98753a5a1b3Sopenharmony_ci return -1; 98853a5a1b3Sopenharmony_ci 98953a5a1b3Sopenharmony_ci switch (code) { 99053a5a1b3Sopenharmony_ci 99153a5a1b3Sopenharmony_ci case CONNECTION_MESSAGE_REVOKE: 99253a5a1b3Sopenharmony_ci pa_pstream_send_revoke(c->pstream, PA_PTR_TO_UINT(userdata)); 99353a5a1b3Sopenharmony_ci break; 99453a5a1b3Sopenharmony_ci 99553a5a1b3Sopenharmony_ci case CONNECTION_MESSAGE_RELEASE: 99653a5a1b3Sopenharmony_ci pa_pstream_send_release(c->pstream, PA_PTR_TO_UINT(userdata)); 99753a5a1b3Sopenharmony_ci break; 99853a5a1b3Sopenharmony_ci } 99953a5a1b3Sopenharmony_ci 100053a5a1b3Sopenharmony_ci return 0; 100153a5a1b3Sopenharmony_ci} 100253a5a1b3Sopenharmony_ci 100353a5a1b3Sopenharmony_ci/* Called from main context */ 100453a5a1b3Sopenharmony_cistatic void native_connection_unlink(pa_native_connection *c) { 100553a5a1b3Sopenharmony_ci record_stream *r; 100653a5a1b3Sopenharmony_ci output_stream *o; 100753a5a1b3Sopenharmony_ci 100853a5a1b3Sopenharmony_ci pa_assert(c); 100953a5a1b3Sopenharmony_ci 101053a5a1b3Sopenharmony_ci if (!c->protocol) 101153a5a1b3Sopenharmony_ci return; 101253a5a1b3Sopenharmony_ci 101353a5a1b3Sopenharmony_ci pa_hook_fire(&c->protocol->hooks[PA_NATIVE_HOOK_CONNECTION_UNLINK], c); 101453a5a1b3Sopenharmony_ci 101553a5a1b3Sopenharmony_ci if (c->options) 101653a5a1b3Sopenharmony_ci pa_native_options_unref(c->options); 101753a5a1b3Sopenharmony_ci 101853a5a1b3Sopenharmony_ci if (c->srbpending) 101953a5a1b3Sopenharmony_ci pa_srbchannel_free(c->srbpending); 102053a5a1b3Sopenharmony_ci 102153a5a1b3Sopenharmony_ci while ((r = pa_idxset_first(c->record_streams, NULL))) 102253a5a1b3Sopenharmony_ci record_stream_unlink(r); 102353a5a1b3Sopenharmony_ci 102453a5a1b3Sopenharmony_ci while ((o = pa_idxset_first(c->output_streams, NULL))) 102553a5a1b3Sopenharmony_ci if (playback_stream_isinstance(o)) 102653a5a1b3Sopenharmony_ci playback_stream_unlink(PLAYBACK_STREAM(o)); 102753a5a1b3Sopenharmony_ci else 102853a5a1b3Sopenharmony_ci upload_stream_unlink(UPLOAD_STREAM(o)); 102953a5a1b3Sopenharmony_ci 103053a5a1b3Sopenharmony_ci if (c->subscription) 103153a5a1b3Sopenharmony_ci pa_subscription_free(c->subscription); 103253a5a1b3Sopenharmony_ci 103353a5a1b3Sopenharmony_ci if (c->pstream) 103453a5a1b3Sopenharmony_ci pa_pstream_unlink(c->pstream); 103553a5a1b3Sopenharmony_ci 103653a5a1b3Sopenharmony_ci if (c->auth_timeout_event) { 103753a5a1b3Sopenharmony_ci c->protocol->core->mainloop->time_free(c->auth_timeout_event); 103853a5a1b3Sopenharmony_ci c->auth_timeout_event = NULL; 103953a5a1b3Sopenharmony_ci } 104053a5a1b3Sopenharmony_ci 104153a5a1b3Sopenharmony_ci pa_assert_se(pa_idxset_remove_by_data(c->protocol->connections, c, NULL) == c); 104253a5a1b3Sopenharmony_ci c->protocol = NULL; 104353a5a1b3Sopenharmony_ci pa_native_connection_unref(c); 104453a5a1b3Sopenharmony_ci} 104553a5a1b3Sopenharmony_ci 104653a5a1b3Sopenharmony_ci/* Called from main context */ 104753a5a1b3Sopenharmony_cistatic void native_connection_free(pa_object *o) { 104853a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(o); 104953a5a1b3Sopenharmony_ci 105053a5a1b3Sopenharmony_ci pa_assert(c); 105153a5a1b3Sopenharmony_ci 105253a5a1b3Sopenharmony_ci native_connection_unlink(c); 105353a5a1b3Sopenharmony_ci 105453a5a1b3Sopenharmony_ci pa_idxset_free(c->record_streams, NULL); 105553a5a1b3Sopenharmony_ci pa_idxset_free(c->output_streams, NULL); 105653a5a1b3Sopenharmony_ci 105753a5a1b3Sopenharmony_ci pa_pdispatch_unref(c->pdispatch); 105853a5a1b3Sopenharmony_ci pa_pstream_unref(c->pstream); 105953a5a1b3Sopenharmony_ci if (c->rw_mempool) 106053a5a1b3Sopenharmony_ci pa_mempool_unref(c->rw_mempool); 106153a5a1b3Sopenharmony_ci 106253a5a1b3Sopenharmony_ci pa_client_free(c->client); 106353a5a1b3Sopenharmony_ci 106453a5a1b3Sopenharmony_ci pa_xfree(c); 106553a5a1b3Sopenharmony_ci} 106653a5a1b3Sopenharmony_ci 106753a5a1b3Sopenharmony_ci/* Called from main context */ 106853a5a1b3Sopenharmony_cistatic void native_connection_send_memblock(pa_native_connection *c) { 106953a5a1b3Sopenharmony_ci uint32_t start; 107053a5a1b3Sopenharmony_ci record_stream *r; 107153a5a1b3Sopenharmony_ci 107253a5a1b3Sopenharmony_ci start = PA_IDXSET_INVALID; 107353a5a1b3Sopenharmony_ci for (;;) { 107453a5a1b3Sopenharmony_ci pa_memchunk chunk; 107553a5a1b3Sopenharmony_ci 107653a5a1b3Sopenharmony_ci if (!(r = RECORD_STREAM(pa_idxset_rrobin(c->record_streams, &c->rrobin_index)))) 107753a5a1b3Sopenharmony_ci return; 107853a5a1b3Sopenharmony_ci 107953a5a1b3Sopenharmony_ci if (start == PA_IDXSET_INVALID) 108053a5a1b3Sopenharmony_ci start = c->rrobin_index; 108153a5a1b3Sopenharmony_ci else if (start == c->rrobin_index) 108253a5a1b3Sopenharmony_ci return; 108353a5a1b3Sopenharmony_ci 108453a5a1b3Sopenharmony_ci if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) { 108553a5a1b3Sopenharmony_ci pa_memchunk schunk = chunk; 108653a5a1b3Sopenharmony_ci 108753a5a1b3Sopenharmony_ci if (schunk.length > r->buffer_attr.fragsize) 108853a5a1b3Sopenharmony_ci schunk.length = r->buffer_attr.fragsize; 108953a5a1b3Sopenharmony_ci 109053a5a1b3Sopenharmony_ci pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk); 109153a5a1b3Sopenharmony_ci 109253a5a1b3Sopenharmony_ci pa_memblockq_drop(r->memblockq, schunk.length); 109353a5a1b3Sopenharmony_ci pa_memblock_unref(schunk.memblock); 109453a5a1b3Sopenharmony_ci 109553a5a1b3Sopenharmony_ci return; 109653a5a1b3Sopenharmony_ci } 109753a5a1b3Sopenharmony_ci } 109853a5a1b3Sopenharmony_ci} 109953a5a1b3Sopenharmony_ci 110053a5a1b3Sopenharmony_ci/*** sink input callbacks ***/ 110153a5a1b3Sopenharmony_ci 110253a5a1b3Sopenharmony_ci/* Called from thread context */ 110353a5a1b3Sopenharmony_cistatic void handle_seek(playback_stream *s, int64_t indexw) { 110453a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 110553a5a1b3Sopenharmony_ci 110653a5a1b3Sopenharmony_ci/* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */ 110753a5a1b3Sopenharmony_ci 110853a5a1b3Sopenharmony_ci if (s->sink_input->thread_info.underrun_for > 0) { 110953a5a1b3Sopenharmony_ci 111053a5a1b3Sopenharmony_ci/* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */ 111153a5a1b3Sopenharmony_ci 111253a5a1b3Sopenharmony_ci if (pa_memblockq_is_readable(s->memblockq)) { 111353a5a1b3Sopenharmony_ci 111453a5a1b3Sopenharmony_ci /* We just ended an underrun, let's ask the sink 111553a5a1b3Sopenharmony_ci * for a complete rewind rewrite */ 111653a5a1b3Sopenharmony_ci 111753a5a1b3Sopenharmony_ci pa_log_debug("Requesting rewind due to end of underrun."); 111853a5a1b3Sopenharmony_ci pa_sink_input_request_rewind(s->sink_input, 111953a5a1b3Sopenharmony_ci (size_t) (s->sink_input->thread_info.underrun_for == (uint64_t) -1 ? 0 : 112053a5a1b3Sopenharmony_ci s->sink_input->thread_info.underrun_for), 112153a5a1b3Sopenharmony_ci false, true, false); 112253a5a1b3Sopenharmony_ci } 112353a5a1b3Sopenharmony_ci 112453a5a1b3Sopenharmony_ci } else { 112553a5a1b3Sopenharmony_ci int64_t indexr; 112653a5a1b3Sopenharmony_ci 112753a5a1b3Sopenharmony_ci indexr = pa_memblockq_get_read_index(s->memblockq); 112853a5a1b3Sopenharmony_ci 112953a5a1b3Sopenharmony_ci if (indexw < indexr) { 113053a5a1b3Sopenharmony_ci /* OK, the sink already asked for this data, so 113153a5a1b3Sopenharmony_ci * let's have it ask us again */ 113253a5a1b3Sopenharmony_ci 113353a5a1b3Sopenharmony_ci pa_log_debug("Requesting rewind due to rewrite."); 113453a5a1b3Sopenharmony_ci pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), true, false, false); 113553a5a1b3Sopenharmony_ci } 113653a5a1b3Sopenharmony_ci } 113753a5a1b3Sopenharmony_ci 113853a5a1b3Sopenharmony_ci playback_stream_request_bytes(s); 113953a5a1b3Sopenharmony_ci} 114053a5a1b3Sopenharmony_ci 114153a5a1b3Sopenharmony_cistatic void flush_write_no_account(pa_memblockq *q) { 114253a5a1b3Sopenharmony_ci pa_memblockq_flush_write(q, false); 114353a5a1b3Sopenharmony_ci} 114453a5a1b3Sopenharmony_ci 114553a5a1b3Sopenharmony_ci/* Called from thread context */ 114653a5a1b3Sopenharmony_cistatic int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { 114753a5a1b3Sopenharmony_ci pa_sink_input *i = PA_SINK_INPUT(o); 114853a5a1b3Sopenharmony_ci playback_stream *s; 114953a5a1b3Sopenharmony_ci 115053a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 115153a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 115253a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 115353a5a1b3Sopenharmony_ci 115453a5a1b3Sopenharmony_ci switch (code) { 115553a5a1b3Sopenharmony_ci 115653a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_SEEK: 115753a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_POST_DATA: { 115853a5a1b3Sopenharmony_ci int64_t windex = pa_memblockq_get_write_index(s->memblockq); 115953a5a1b3Sopenharmony_ci 116053a5a1b3Sopenharmony_ci if (code == SINK_INPUT_MESSAGE_SEEK) { 116153a5a1b3Sopenharmony_ci /* The client side is incapable of accounting correctly 116253a5a1b3Sopenharmony_ci * for seeks of a type != PA_SEEK_RELATIVE. We need to be 116353a5a1b3Sopenharmony_ci * able to deal with that. */ 116453a5a1b3Sopenharmony_ci 116553a5a1b3Sopenharmony_ci pa_memblockq_seek(s->memblockq, offset, PA_PTR_TO_UINT(userdata), PA_PTR_TO_UINT(userdata) == PA_SEEK_RELATIVE); 116653a5a1b3Sopenharmony_ci windex = PA_MIN(windex, pa_memblockq_get_write_index(s->memblockq)); 116753a5a1b3Sopenharmony_ci } 116853a5a1b3Sopenharmony_ci 116953a5a1b3Sopenharmony_ci if (chunk && pa_memblockq_push_align(s->memblockq, chunk) < 0) { 117053a5a1b3Sopenharmony_ci if (pa_log_ratelimit(PA_LOG_WARN)) 117153a5a1b3Sopenharmony_ci pa_log_warn("Failed to push data into queue"); 117253a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL); 117353a5a1b3Sopenharmony_ci pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE, true); 117453a5a1b3Sopenharmony_ci } 117553a5a1b3Sopenharmony_ci 117653a5a1b3Sopenharmony_ci /* If more data is in queue, we rewind later instead. */ 117753a5a1b3Sopenharmony_ci if (s->seek_windex != -1) 117853a5a1b3Sopenharmony_ci windex = PA_MIN(windex, s->seek_windex); 117953a5a1b3Sopenharmony_ci if (pa_atomic_dec(&s->seek_or_post_in_queue) > 1) 118053a5a1b3Sopenharmony_ci s->seek_windex = windex; 118153a5a1b3Sopenharmony_ci else { 118253a5a1b3Sopenharmony_ci s->seek_windex = -1; 118353a5a1b3Sopenharmony_ci handle_seek(s, windex); 118453a5a1b3Sopenharmony_ci } 118553a5a1b3Sopenharmony_ci return 0; 118653a5a1b3Sopenharmony_ci } 118753a5a1b3Sopenharmony_ci 118853a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_DRAIN: 118953a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_FLUSH: 119053a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_PREBUF_FORCE: 119153a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_TRIGGER: { 119253a5a1b3Sopenharmony_ci 119353a5a1b3Sopenharmony_ci int64_t windex; 119453a5a1b3Sopenharmony_ci pa_sink_input *isync; 119553a5a1b3Sopenharmony_ci void (*func)(pa_memblockq *bq); 119653a5a1b3Sopenharmony_ci 119753a5a1b3Sopenharmony_ci switch (code) { 119853a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_FLUSH: 119953a5a1b3Sopenharmony_ci func = flush_write_no_account; 120053a5a1b3Sopenharmony_ci break; 120153a5a1b3Sopenharmony_ci 120253a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_PREBUF_FORCE: 120353a5a1b3Sopenharmony_ci func = pa_memblockq_prebuf_force; 120453a5a1b3Sopenharmony_ci break; 120553a5a1b3Sopenharmony_ci 120653a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_DRAIN: 120753a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_TRIGGER: 120853a5a1b3Sopenharmony_ci func = pa_memblockq_prebuf_disable; 120953a5a1b3Sopenharmony_ci break; 121053a5a1b3Sopenharmony_ci 121153a5a1b3Sopenharmony_ci default: 121253a5a1b3Sopenharmony_ci pa_assert_not_reached(); 121353a5a1b3Sopenharmony_ci } 121453a5a1b3Sopenharmony_ci 121553a5a1b3Sopenharmony_ci windex = pa_memblockq_get_write_index(s->memblockq); 121653a5a1b3Sopenharmony_ci func(s->memblockq); 121753a5a1b3Sopenharmony_ci handle_seek(s, windex); 121853a5a1b3Sopenharmony_ci 121953a5a1b3Sopenharmony_ci /* Do the same for all other members in the sync group */ 122053a5a1b3Sopenharmony_ci for (isync = i->sync_prev; isync; isync = isync->sync_prev) { 122153a5a1b3Sopenharmony_ci playback_stream *ssync = PLAYBACK_STREAM(isync->userdata); 122253a5a1b3Sopenharmony_ci windex = pa_memblockq_get_write_index(ssync->memblockq); 122353a5a1b3Sopenharmony_ci func(ssync->memblockq); 122453a5a1b3Sopenharmony_ci handle_seek(ssync, windex); 122553a5a1b3Sopenharmony_ci } 122653a5a1b3Sopenharmony_ci 122753a5a1b3Sopenharmony_ci for (isync = i->sync_next; isync; isync = isync->sync_next) { 122853a5a1b3Sopenharmony_ci playback_stream *ssync = PLAYBACK_STREAM(isync->userdata); 122953a5a1b3Sopenharmony_ci windex = pa_memblockq_get_write_index(ssync->memblockq); 123053a5a1b3Sopenharmony_ci func(ssync->memblockq); 123153a5a1b3Sopenharmony_ci handle_seek(ssync, windex); 123253a5a1b3Sopenharmony_ci } 123353a5a1b3Sopenharmony_ci 123453a5a1b3Sopenharmony_ci if (code == SINK_INPUT_MESSAGE_DRAIN) { 123553a5a1b3Sopenharmony_ci if (!pa_memblockq_is_readable(s->memblockq)) 123653a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, userdata, 0, NULL, NULL); 123753a5a1b3Sopenharmony_ci else { 123853a5a1b3Sopenharmony_ci s->drain_tag = PA_PTR_TO_UINT(userdata); 123953a5a1b3Sopenharmony_ci s->drain_request = true; 124053a5a1b3Sopenharmony_ci } 124153a5a1b3Sopenharmony_ci } 124253a5a1b3Sopenharmony_ci 124353a5a1b3Sopenharmony_ci return 0; 124453a5a1b3Sopenharmony_ci } 124553a5a1b3Sopenharmony_ci 124653a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_UPDATE_LATENCY: 124753a5a1b3Sopenharmony_ci /* Atomically get a snapshot of all timing parameters... */ 124853a5a1b3Sopenharmony_ci s->read_index = pa_memblockq_get_read_index(s->memblockq); 124953a5a1b3Sopenharmony_ci s->write_index = pa_memblockq_get_write_index(s->memblockq); 125053a5a1b3Sopenharmony_ci s->render_memblockq_length = pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq); 125153a5a1b3Sopenharmony_ci s->current_sink_latency = pa_sink_get_latency_within_thread(s->sink_input->sink, false); 125253a5a1b3Sopenharmony_ci /* Add resampler latency */ 125353a5a1b3Sopenharmony_ci s->current_sink_latency += pa_resampler_get_delay_usec(i->thread_info.resampler); 125453a5a1b3Sopenharmony_ci s->underrun_for = s->sink_input->thread_info.underrun_for; 125553a5a1b3Sopenharmony_ci s->playing_for = s->sink_input->thread_info.playing_for; 125653a5a1b3Sopenharmony_ci 125753a5a1b3Sopenharmony_ci return 0; 125853a5a1b3Sopenharmony_ci 125953a5a1b3Sopenharmony_ci case PA_SINK_INPUT_MESSAGE_SET_STATE: { 126053a5a1b3Sopenharmony_ci int64_t windex; 126153a5a1b3Sopenharmony_ci 126253a5a1b3Sopenharmony_ci windex = pa_memblockq_get_write_index(s->memblockq); 126353a5a1b3Sopenharmony_ci 126453a5a1b3Sopenharmony_ci /* We enable prebuffering so that after CORKED -> RUNNING 126553a5a1b3Sopenharmony_ci * transitions we don't have trouble with underruns in case the 126653a5a1b3Sopenharmony_ci * buffer has too little data. This must not be done when draining 126753a5a1b3Sopenharmony_ci * has been requested, however, otherwise the buffered audio would 126853a5a1b3Sopenharmony_ci * never play. */ 126953a5a1b3Sopenharmony_ci if (!s->drain_request) 127053a5a1b3Sopenharmony_ci pa_memblockq_prebuf_force(s->memblockq); 127153a5a1b3Sopenharmony_ci 127253a5a1b3Sopenharmony_ci handle_seek(s, windex); 127353a5a1b3Sopenharmony_ci 127453a5a1b3Sopenharmony_ci /* Fall through to the default handler */ 127553a5a1b3Sopenharmony_ci break; 127653a5a1b3Sopenharmony_ci } 127753a5a1b3Sopenharmony_ci 127853a5a1b3Sopenharmony_ci case PA_SINK_INPUT_MESSAGE_GET_LATENCY: { 127953a5a1b3Sopenharmony_ci pa_usec_t *r = userdata; 128053a5a1b3Sopenharmony_ci 128153a5a1b3Sopenharmony_ci *r = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec); 128253a5a1b3Sopenharmony_ci 128353a5a1b3Sopenharmony_ci /* Fall through, the default handler will add in the extra 128453a5a1b3Sopenharmony_ci * latency added by the resampler */ 128553a5a1b3Sopenharmony_ci break; 128653a5a1b3Sopenharmony_ci } 128753a5a1b3Sopenharmony_ci 128853a5a1b3Sopenharmony_ci case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: { 128953a5a1b3Sopenharmony_ci pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr); 129053a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 129153a5a1b3Sopenharmony_ci return 0; 129253a5a1b3Sopenharmony_ci } 129353a5a1b3Sopenharmony_ci } 129453a5a1b3Sopenharmony_ci 129553a5a1b3Sopenharmony_ci return pa_sink_input_process_msg(o, code, userdata, offset, chunk); 129653a5a1b3Sopenharmony_ci} 129753a5a1b3Sopenharmony_ci 129853a5a1b3Sopenharmony_cistatic bool handle_input_underrun(playback_stream *s, bool force) { 129953a5a1b3Sopenharmony_ci bool send_drain; 130053a5a1b3Sopenharmony_ci 130153a5a1b3Sopenharmony_ci if (pa_memblockq_is_readable(s->memblockq)) 130253a5a1b3Sopenharmony_ci return false; 130353a5a1b3Sopenharmony_ci 130453a5a1b3Sopenharmony_ci if (!s->is_underrun) 130553a5a1b3Sopenharmony_ci pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit", 130653a5a1b3Sopenharmony_ci s->drain_request ? "drain" : "underrun", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME))); 130753a5a1b3Sopenharmony_ci 130853a5a1b3Sopenharmony_ci send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input)); 130953a5a1b3Sopenharmony_ci 131053a5a1b3Sopenharmony_ci if (send_drain) { 131153a5a1b3Sopenharmony_ci s->drain_request = false; 131253a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_DRAIN_ACK, PA_UINT_TO_PTR(s->drain_tag), 0, NULL, NULL); 131353a5a1b3Sopenharmony_ci pa_log_debug("Drain acknowledged of '%s'", pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME))); 131453a5a1b3Sopenharmony_ci } else if (!s->is_underrun) { 131553a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW, NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL); 131653a5a1b3Sopenharmony_ci } 131753a5a1b3Sopenharmony_ci s->is_underrun = true; 131853a5a1b3Sopenharmony_ci playback_stream_request_bytes(s); 131953a5a1b3Sopenharmony_ci return true; 132053a5a1b3Sopenharmony_ci} 132153a5a1b3Sopenharmony_ci 132253a5a1b3Sopenharmony_ci/* Called from thread context */ 132353a5a1b3Sopenharmony_cistatic bool sink_input_process_underrun_cb(pa_sink_input *i) { 132453a5a1b3Sopenharmony_ci playback_stream *s; 132553a5a1b3Sopenharmony_ci 132653a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 132753a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 132853a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 132953a5a1b3Sopenharmony_ci 133053a5a1b3Sopenharmony_ci return handle_input_underrun(s, true); 133153a5a1b3Sopenharmony_ci} 133253a5a1b3Sopenharmony_ci 133353a5a1b3Sopenharmony_cistatic bool handle_input_underrun_ohos(playback_stream *s, bool force) { 133453a5a1b3Sopenharmony_ci bool send_drain; 133553a5a1b3Sopenharmony_ci 133653a5a1b3Sopenharmony_ci if (pa_memblockq_is_readable(s->memblockq)) 133753a5a1b3Sopenharmony_ci return false; 133853a5a1b3Sopenharmony_ci 133953a5a1b3Sopenharmony_ci if (!s->is_underrun) 134053a5a1b3Sopenharmony_ci pa_log_debug("%s %s of '%s'", force ? "Actual" : "Implicit", 134153a5a1b3Sopenharmony_ci s->drain_request ? "drain" : "underrun", 134253a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(s->sink_input->proplist, PA_PROP_MEDIA_NAME))); 134353a5a1b3Sopenharmony_ci 134453a5a1b3Sopenharmony_ci send_drain = s->drain_request && (force || pa_sink_input_safe_to_remove(s->sink_input)); 134553a5a1b3Sopenharmony_ci if (!send_drain) { 134653a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UNDERFLOW_OHOS, 134753a5a1b3Sopenharmony_ci NULL, pa_memblockq_get_read_index(s->memblockq), NULL, NULL); 134853a5a1b3Sopenharmony_ci } 134953a5a1b3Sopenharmony_ci return true; 135053a5a1b3Sopenharmony_ci} 135153a5a1b3Sopenharmony_ci 135253a5a1b3Sopenharmony_cistatic bool sink_input_process_underrun_ohos_cb(pa_sink_input *i) { 135353a5a1b3Sopenharmony_ci playback_stream *s; 135453a5a1b3Sopenharmony_ci 135553a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 135653a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 135753a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 135853a5a1b3Sopenharmony_ci 135953a5a1b3Sopenharmony_ci return handle_input_underrun_ohos(s, true); 136053a5a1b3Sopenharmony_ci} 136153a5a1b3Sopenharmony_ci 136253a5a1b3Sopenharmony_ci/* Called from thread context */ 136353a5a1b3Sopenharmony_cistatic int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk) { 136453a5a1b3Sopenharmony_ci playback_stream *s; 136553a5a1b3Sopenharmony_ci 136653a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 136753a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 136853a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 136953a5a1b3Sopenharmony_ci pa_assert(chunk); 137053a5a1b3Sopenharmony_ci 137153a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 137253a5a1b3Sopenharmony_ci pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); 137353a5a1b3Sopenharmony_ci#endif 137453a5a1b3Sopenharmony_ci 137553a5a1b3Sopenharmony_ci if (!handle_input_underrun(s, false)) 137653a5a1b3Sopenharmony_ci s->is_underrun = false; 137753a5a1b3Sopenharmony_ci 137853a5a1b3Sopenharmony_ci /* This call will not fail with prebuf=0, hence we check for 137953a5a1b3Sopenharmony_ci underrun explicitly in handle_input_underrun */ 138053a5a1b3Sopenharmony_ci if (pa_memblockq_peek(s->memblockq, chunk) < 0) 138153a5a1b3Sopenharmony_ci return -1; 138253a5a1b3Sopenharmony_ci 138353a5a1b3Sopenharmony_ci chunk->length = PA_MIN(nbytes, chunk->length); 138453a5a1b3Sopenharmony_ci 138553a5a1b3Sopenharmony_ci if (i->thread_info.underrun_for > 0) 138653a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_STARTED, NULL, 0, NULL, NULL); 138753a5a1b3Sopenharmony_ci 138853a5a1b3Sopenharmony_ci pa_memblockq_drop(s->memblockq, chunk->length); 138953a5a1b3Sopenharmony_ci playback_stream_request_bytes(s); 139053a5a1b3Sopenharmony_ci 139153a5a1b3Sopenharmony_ci return 0; 139253a5a1b3Sopenharmony_ci} 139353a5a1b3Sopenharmony_ci 139453a5a1b3Sopenharmony_ci/* Called from thread context */ 139553a5a1b3Sopenharmony_cistatic void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) { 139653a5a1b3Sopenharmony_ci playback_stream *s; 139753a5a1b3Sopenharmony_ci 139853a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 139953a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 140053a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 140153a5a1b3Sopenharmony_ci 140253a5a1b3Sopenharmony_ci /* If we are in an underrun, then we don't rewind */ 140353a5a1b3Sopenharmony_ci if (i->thread_info.underrun_for > 0) 140453a5a1b3Sopenharmony_ci return; 140553a5a1b3Sopenharmony_ci 140653a5a1b3Sopenharmony_ci pa_memblockq_rewind(s->memblockq, nbytes); 140753a5a1b3Sopenharmony_ci} 140853a5a1b3Sopenharmony_ci 140953a5a1b3Sopenharmony_ci/* Called from thread context */ 141053a5a1b3Sopenharmony_cistatic void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) { 141153a5a1b3Sopenharmony_ci playback_stream *s; 141253a5a1b3Sopenharmony_ci 141353a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 141453a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 141553a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 141653a5a1b3Sopenharmony_ci 141753a5a1b3Sopenharmony_ci pa_memblockq_set_maxrewind(s->memblockq, nbytes); 141853a5a1b3Sopenharmony_ci} 141953a5a1b3Sopenharmony_ci 142053a5a1b3Sopenharmony_ci/* Called from thread context */ 142153a5a1b3Sopenharmony_cistatic void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) { 142253a5a1b3Sopenharmony_ci playback_stream *s; 142353a5a1b3Sopenharmony_ci size_t new_tlength, old_tlength; 142453a5a1b3Sopenharmony_ci 142553a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 142653a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 142753a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 142853a5a1b3Sopenharmony_ci 142953a5a1b3Sopenharmony_ci old_tlength = pa_memblockq_get_tlength(s->memblockq); 143053a5a1b3Sopenharmony_ci new_tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq); 143153a5a1b3Sopenharmony_ci 143253a5a1b3Sopenharmony_ci if (old_tlength < new_tlength) { 143353a5a1b3Sopenharmony_ci pa_log_debug("max_request changed, trying to update from %zu to %zu.", old_tlength, 143453a5a1b3Sopenharmony_ci new_tlength); 143553a5a1b3Sopenharmony_ci pa_memblockq_set_tlength(s->memblockq, new_tlength); 143653a5a1b3Sopenharmony_ci new_tlength = pa_memblockq_get_tlength(s->memblockq); 143753a5a1b3Sopenharmony_ci 143853a5a1b3Sopenharmony_ci if (new_tlength == old_tlength) 143953a5a1b3Sopenharmony_ci pa_log_debug("Failed to increase tlength"); 144053a5a1b3Sopenharmony_ci else { 144153a5a1b3Sopenharmony_ci pa_log_debug("Notifying client about increased tlength"); 144253a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH, NULL, pa_memblockq_get_tlength(s->memblockq), NULL, NULL); 144353a5a1b3Sopenharmony_ci } 144453a5a1b3Sopenharmony_ci } 144553a5a1b3Sopenharmony_ci} 144653a5a1b3Sopenharmony_ci 144753a5a1b3Sopenharmony_ci/* Called from main context */ 144853a5a1b3Sopenharmony_cistatic void sink_input_kill_cb(pa_sink_input *i) { 144953a5a1b3Sopenharmony_ci playback_stream *s; 145053a5a1b3Sopenharmony_ci 145153a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 145253a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 145353a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 145453a5a1b3Sopenharmony_ci 145553a5a1b3Sopenharmony_ci playback_stream_send_killed(s); 145653a5a1b3Sopenharmony_ci playback_stream_unlink(s); 145753a5a1b3Sopenharmony_ci} 145853a5a1b3Sopenharmony_ci 145953a5a1b3Sopenharmony_ci/* Called from main context */ 146053a5a1b3Sopenharmony_cistatic void sink_input_send_event_cb(pa_sink_input *i, const char *event, pa_proplist *pl) { 146153a5a1b3Sopenharmony_ci playback_stream *s; 146253a5a1b3Sopenharmony_ci pa_tagstruct *t; 146353a5a1b3Sopenharmony_ci 146453a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 146553a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 146653a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 146753a5a1b3Sopenharmony_ci 146853a5a1b3Sopenharmony_ci if (s->connection->version < 15) 146953a5a1b3Sopenharmony_ci return; 147053a5a1b3Sopenharmony_ci 147153a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 147253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_EVENT); 147353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 147453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 147553a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, event); 147653a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, pl); 147753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 147853a5a1b3Sopenharmony_ci} 147953a5a1b3Sopenharmony_ci 148053a5a1b3Sopenharmony_ci/* Called from main context */ 148153a5a1b3Sopenharmony_cistatic void sink_input_suspend_cb(pa_sink_input *i, pa_sink_state_t old_state, pa_suspend_cause_t old_suspend_cause) { 148253a5a1b3Sopenharmony_ci playback_stream *s; 148353a5a1b3Sopenharmony_ci pa_tagstruct *t; 148453a5a1b3Sopenharmony_ci bool suspend; 148553a5a1b3Sopenharmony_ci 148653a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 148753a5a1b3Sopenharmony_ci 148853a5a1b3Sopenharmony_ci /* State has not changed, nothing to do */ 148953a5a1b3Sopenharmony_ci if (old_state == i->sink->state) 149053a5a1b3Sopenharmony_ci return; 149153a5a1b3Sopenharmony_ci 149253a5a1b3Sopenharmony_ci suspend = (i->sink->state == PA_SINK_SUSPENDED); 149353a5a1b3Sopenharmony_ci 149453a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 149553a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 149653a5a1b3Sopenharmony_ci 149753a5a1b3Sopenharmony_ci if (s->connection->version < 12) 149853a5a1b3Sopenharmony_ci return; 149953a5a1b3Sopenharmony_ci 150053a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 150153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_SUSPENDED); 150253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 150353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 150453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, suspend); 150553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 150653a5a1b3Sopenharmony_ci} 150753a5a1b3Sopenharmony_ci 150853a5a1b3Sopenharmony_ci/* Called from main context */ 150953a5a1b3Sopenharmony_cistatic void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { 151053a5a1b3Sopenharmony_ci playback_stream *s; 151153a5a1b3Sopenharmony_ci pa_tagstruct *t; 151253a5a1b3Sopenharmony_ci 151353a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(i); 151453a5a1b3Sopenharmony_ci s = PLAYBACK_STREAM(i->userdata); 151553a5a1b3Sopenharmony_ci playback_stream_assert_ref(s); 151653a5a1b3Sopenharmony_ci 151753a5a1b3Sopenharmony_ci if (!dest) 151853a5a1b3Sopenharmony_ci return; 151953a5a1b3Sopenharmony_ci 152053a5a1b3Sopenharmony_ci fix_playback_buffer_attr(s); 152153a5a1b3Sopenharmony_ci pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr); 152253a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 152353a5a1b3Sopenharmony_ci 152453a5a1b3Sopenharmony_ci if (s->connection->version < 12) 152553a5a1b3Sopenharmony_ci return; 152653a5a1b3Sopenharmony_ci 152753a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 152853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_STREAM_MOVED); 152953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 153053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 153153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, dest->index); 153253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, dest->name); 153353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, dest->state == PA_SINK_SUSPENDED); 153453a5a1b3Sopenharmony_ci 153553a5a1b3Sopenharmony_ci if (s->connection->version >= 13) { 153653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.maxlength); 153753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.tlength); 153853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.prebuf); 153953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.minreq); 154053a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, s->configured_sink_latency); 154153a5a1b3Sopenharmony_ci } 154253a5a1b3Sopenharmony_ci 154353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 154453a5a1b3Sopenharmony_ci} 154553a5a1b3Sopenharmony_ci 154653a5a1b3Sopenharmony_ci/*** source_output callbacks ***/ 154753a5a1b3Sopenharmony_ci 154853a5a1b3Sopenharmony_ci/* Called from thread context */ 154953a5a1b3Sopenharmony_cistatic int source_output_process_msg(pa_msgobject *_o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { 155053a5a1b3Sopenharmony_ci pa_source_output *o = PA_SOURCE_OUTPUT(_o); 155153a5a1b3Sopenharmony_ci record_stream *s; 155253a5a1b3Sopenharmony_ci 155353a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 155453a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 155553a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 155653a5a1b3Sopenharmony_ci 155753a5a1b3Sopenharmony_ci switch (code) { 155853a5a1b3Sopenharmony_ci case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY: 155953a5a1b3Sopenharmony_ci /* Atomically get a snapshot of all timing parameters... */ 156053a5a1b3Sopenharmony_ci s->current_monitor_latency = o->source->monitor_of ? pa_sink_get_latency_within_thread(o->source->monitor_of, false) : 0; 156153a5a1b3Sopenharmony_ci s->current_source_latency = pa_source_get_latency_within_thread(o->source, false); 156253a5a1b3Sopenharmony_ci /* Add resampler latency */ 156353a5a1b3Sopenharmony_ci s->current_source_latency += pa_resampler_get_delay_usec(o->thread_info.resampler); 156453a5a1b3Sopenharmony_ci s->on_the_fly_snapshot = pa_atomic_load(&s->on_the_fly); 156553a5a1b3Sopenharmony_ci return 0; 156653a5a1b3Sopenharmony_ci } 156753a5a1b3Sopenharmony_ci 156853a5a1b3Sopenharmony_ci return pa_source_output_process_msg(_o, code, userdata, offset, chunk); 156953a5a1b3Sopenharmony_ci} 157053a5a1b3Sopenharmony_ci 157153a5a1b3Sopenharmony_ci/* Called from thread context */ 157253a5a1b3Sopenharmony_cistatic void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) { 157353a5a1b3Sopenharmony_ci record_stream *s; 157453a5a1b3Sopenharmony_ci 157553a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 157653a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 157753a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 157853a5a1b3Sopenharmony_ci pa_assert(chunk); 157953a5a1b3Sopenharmony_ci 158053a5a1b3Sopenharmony_ci pa_atomic_add(&s->on_the_fly, chunk->length); 158153a5a1b3Sopenharmony_ci pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), RECORD_STREAM_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); 158253a5a1b3Sopenharmony_ci} 158353a5a1b3Sopenharmony_ci 158453a5a1b3Sopenharmony_cistatic void source_output_kill_cb(pa_source_output *o) { 158553a5a1b3Sopenharmony_ci record_stream *s; 158653a5a1b3Sopenharmony_ci 158753a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 158853a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 158953a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 159053a5a1b3Sopenharmony_ci 159153a5a1b3Sopenharmony_ci record_stream_send_killed(s); 159253a5a1b3Sopenharmony_ci record_stream_unlink(s); 159353a5a1b3Sopenharmony_ci} 159453a5a1b3Sopenharmony_ci 159553a5a1b3Sopenharmony_cistatic pa_usec_t source_output_get_latency_cb(pa_source_output *o) { 159653a5a1b3Sopenharmony_ci record_stream *s; 159753a5a1b3Sopenharmony_ci 159853a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 159953a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 160053a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 160153a5a1b3Sopenharmony_ci 160253a5a1b3Sopenharmony_ci /*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/ 160353a5a1b3Sopenharmony_ci 160453a5a1b3Sopenharmony_ci return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &o->sample_spec); 160553a5a1b3Sopenharmony_ci} 160653a5a1b3Sopenharmony_ci 160753a5a1b3Sopenharmony_ci/* Called from main context */ 160853a5a1b3Sopenharmony_cistatic void source_output_send_event_cb(pa_source_output *o, const char *event, pa_proplist *pl) { 160953a5a1b3Sopenharmony_ci record_stream *s; 161053a5a1b3Sopenharmony_ci pa_tagstruct *t; 161153a5a1b3Sopenharmony_ci 161253a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 161353a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 161453a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 161553a5a1b3Sopenharmony_ci 161653a5a1b3Sopenharmony_ci if (s->connection->version < 15) 161753a5a1b3Sopenharmony_ci return; 161853a5a1b3Sopenharmony_ci 161953a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 162053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_EVENT); 162153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 162253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 162353a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, event); 162453a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, pl); 162553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 162653a5a1b3Sopenharmony_ci} 162753a5a1b3Sopenharmony_ci 162853a5a1b3Sopenharmony_ci/* Called from main context */ 162953a5a1b3Sopenharmony_cistatic void source_output_suspend_cb(pa_source_output *o, pa_source_state_t old_state, pa_suspend_cause_t old_suspend_cause) { 163053a5a1b3Sopenharmony_ci record_stream *s; 163153a5a1b3Sopenharmony_ci pa_tagstruct *t; 163253a5a1b3Sopenharmony_ci bool suspend; 163353a5a1b3Sopenharmony_ci 163453a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 163553a5a1b3Sopenharmony_ci 163653a5a1b3Sopenharmony_ci /* State has not changed, nothing to do */ 163753a5a1b3Sopenharmony_ci if (old_state == o->source->state) 163853a5a1b3Sopenharmony_ci return; 163953a5a1b3Sopenharmony_ci 164053a5a1b3Sopenharmony_ci suspend = (o->source->state == PA_SOURCE_SUSPENDED); 164153a5a1b3Sopenharmony_ci 164253a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 164353a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 164453a5a1b3Sopenharmony_ci 164553a5a1b3Sopenharmony_ci if (s->connection->version < 12) 164653a5a1b3Sopenharmony_ci return; 164753a5a1b3Sopenharmony_ci 164853a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 164953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_SUSPENDED); 165053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 165153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 165253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, suspend); 165353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 165453a5a1b3Sopenharmony_ci} 165553a5a1b3Sopenharmony_ci 165653a5a1b3Sopenharmony_ci/* Called from main context */ 165753a5a1b3Sopenharmony_cistatic void source_output_moving_cb(pa_source_output *o, pa_source *dest) { 165853a5a1b3Sopenharmony_ci record_stream *s; 165953a5a1b3Sopenharmony_ci pa_tagstruct *t; 166053a5a1b3Sopenharmony_ci 166153a5a1b3Sopenharmony_ci pa_source_output_assert_ref(o); 166253a5a1b3Sopenharmony_ci s = RECORD_STREAM(o->userdata); 166353a5a1b3Sopenharmony_ci record_stream_assert_ref(s); 166453a5a1b3Sopenharmony_ci 166553a5a1b3Sopenharmony_ci if (!dest) 166653a5a1b3Sopenharmony_ci return; 166753a5a1b3Sopenharmony_ci 166853a5a1b3Sopenharmony_ci fix_record_buffer_attr_pre(s); 166953a5a1b3Sopenharmony_ci pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength); 167053a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 167153a5a1b3Sopenharmony_ci fix_record_buffer_attr_post(s); 167253a5a1b3Sopenharmony_ci 167353a5a1b3Sopenharmony_ci if (s->connection->version < 12) 167453a5a1b3Sopenharmony_ci return; 167553a5a1b3Sopenharmony_ci 167653a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 167753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_RECORD_STREAM_MOVED); 167853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 167953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 168053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, dest->index); 168153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, dest->name); 168253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, dest->state == PA_SOURCE_SUSPENDED); 168353a5a1b3Sopenharmony_ci 168453a5a1b3Sopenharmony_ci if (s->connection->version >= 13) { 168553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.maxlength); 168653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->buffer_attr.fragsize); 168753a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, s->configured_source_latency); 168853a5a1b3Sopenharmony_ci } 168953a5a1b3Sopenharmony_ci 169053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(s->connection->pstream, t); 169153a5a1b3Sopenharmony_ci} 169253a5a1b3Sopenharmony_ci 169353a5a1b3Sopenharmony_ci/*** pdispatch callbacks ***/ 169453a5a1b3Sopenharmony_ci 169553a5a1b3Sopenharmony_cistatic void protocol_error(pa_native_connection *c) { 169653a5a1b3Sopenharmony_ci pa_log("protocol error, kicking client"); 169753a5a1b3Sopenharmony_ci native_connection_unlink(c); 169853a5a1b3Sopenharmony_ci} 169953a5a1b3Sopenharmony_ci 170053a5a1b3Sopenharmony_ci#define CHECK_VALIDITY(pstream, expression, tag, error) do { \ 170153a5a1b3Sopenharmony_ciif (!(expression)) { \ 170253a5a1b3Sopenharmony_ci pa_pstream_send_error((pstream), (tag), (error)); \ 170353a5a1b3Sopenharmony_ci return; \ 170453a5a1b3Sopenharmony_ci} \ 170553a5a1b3Sopenharmony_ci} while(0); 170653a5a1b3Sopenharmony_ci 170753a5a1b3Sopenharmony_ci#define CHECK_VALIDITY_GOTO(pstream, expression, tag, error, label) do { \ 170853a5a1b3Sopenharmony_ciif (!(expression)) { \ 170953a5a1b3Sopenharmony_ci pa_pstream_send_error((pstream), (tag), (error)); \ 171053a5a1b3Sopenharmony_ci goto label; \ 171153a5a1b3Sopenharmony_ci} \ 171253a5a1b3Sopenharmony_ci} while(0); 171353a5a1b3Sopenharmony_ci 171453a5a1b3Sopenharmony_cistatic pa_tagstruct *reply_new(uint32_t tag) { 171553a5a1b3Sopenharmony_ci pa_tagstruct *reply; 171653a5a1b3Sopenharmony_ci 171753a5a1b3Sopenharmony_ci reply = pa_tagstruct_new(); 171853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_COMMAND_REPLY); 171953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, tag); 172053a5a1b3Sopenharmony_ci return reply; 172153a5a1b3Sopenharmony_ci} 172253a5a1b3Sopenharmony_ci 172353a5a1b3Sopenharmony_cistatic void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 172453a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 172553a5a1b3Sopenharmony_ci playback_stream *s; 172653a5a1b3Sopenharmony_ci uint32_t sink_index, syncid, missing = 0; 172753a5a1b3Sopenharmony_ci pa_buffer_attr attr; 172853a5a1b3Sopenharmony_ci const char *name = NULL, *sink_name; 172953a5a1b3Sopenharmony_ci pa_sample_spec ss; 173053a5a1b3Sopenharmony_ci pa_channel_map map; 173153a5a1b3Sopenharmony_ci pa_tagstruct *reply; 173253a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 173353a5a1b3Sopenharmony_ci pa_cvolume volume; 173453a5a1b3Sopenharmony_ci bool 173553a5a1b3Sopenharmony_ci corked = false, 173653a5a1b3Sopenharmony_ci no_remap = false, 173753a5a1b3Sopenharmony_ci no_remix = false, 173853a5a1b3Sopenharmony_ci fix_format = false, 173953a5a1b3Sopenharmony_ci fix_rate = false, 174053a5a1b3Sopenharmony_ci fix_channels = false, 174153a5a1b3Sopenharmony_ci no_move = false, 174253a5a1b3Sopenharmony_ci variable_rate = false, 174353a5a1b3Sopenharmony_ci muted = false, 174453a5a1b3Sopenharmony_ci adjust_latency = false, 174553a5a1b3Sopenharmony_ci early_requests = false, 174653a5a1b3Sopenharmony_ci dont_inhibit_auto_suspend = false, 174753a5a1b3Sopenharmony_ci volume_set = true, 174853a5a1b3Sopenharmony_ci muted_set = false, 174953a5a1b3Sopenharmony_ci fail_on_suspend = false, 175053a5a1b3Sopenharmony_ci relative_volume = false, 175153a5a1b3Sopenharmony_ci passthrough = false; 175253a5a1b3Sopenharmony_ci 175353a5a1b3Sopenharmony_ci pa_sink_input_flags_t flags = 0; 175453a5a1b3Sopenharmony_ci pa_proplist *p = NULL; 175553a5a1b3Sopenharmony_ci int ret = PA_ERR_INVALID; 175653a5a1b3Sopenharmony_ci uint8_t n_formats = 0; 175753a5a1b3Sopenharmony_ci pa_format_info *format; 175853a5a1b3Sopenharmony_ci pa_idxset *formats = NULL; 175953a5a1b3Sopenharmony_ci uint32_t i; 176053a5a1b3Sopenharmony_ci 176153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 176253a5a1b3Sopenharmony_ci pa_assert(t); 176353a5a1b3Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 176453a5a1b3Sopenharmony_ci 176553a5a1b3Sopenharmony_ci if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) || 176653a5a1b3Sopenharmony_ci pa_tagstruct_get( 176753a5a1b3Sopenharmony_ci t, 176853a5a1b3Sopenharmony_ci PA_TAG_SAMPLE_SPEC, &ss, 176953a5a1b3Sopenharmony_ci PA_TAG_CHANNEL_MAP, &map, 177053a5a1b3Sopenharmony_ci PA_TAG_U32, &sink_index, 177153a5a1b3Sopenharmony_ci PA_TAG_STRING, &sink_name, 177253a5a1b3Sopenharmony_ci PA_TAG_U32, &attr.maxlength, 177353a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, &corked, 177453a5a1b3Sopenharmony_ci PA_TAG_U32, &attr.tlength, 177553a5a1b3Sopenharmony_ci PA_TAG_U32, &attr.prebuf, 177653a5a1b3Sopenharmony_ci PA_TAG_U32, &attr.minreq, 177753a5a1b3Sopenharmony_ci PA_TAG_U32, &syncid, 177853a5a1b3Sopenharmony_ci PA_TAG_CVOLUME, &volume, 177953a5a1b3Sopenharmony_ci PA_TAG_INVALID) < 0) { 178053a5a1b3Sopenharmony_ci 178153a5a1b3Sopenharmony_ci protocol_error(c); 178253a5a1b3Sopenharmony_ci goto finish; 178353a5a1b3Sopenharmony_ci } 178453a5a1b3Sopenharmony_ci 178553a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish); 178653a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID, finish); 178753a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID, finish); 178853a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish); 178953a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish); 179053a5a1b3Sopenharmony_ci 179153a5a1b3Sopenharmony_ci p = pa_proplist_new(); 179253a5a1b3Sopenharmony_ci 179353a5a1b3Sopenharmony_ci if (name) 179453a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name); 179553a5a1b3Sopenharmony_ci 179653a5a1b3Sopenharmony_ci if (c->version >= 12) { 179753a5a1b3Sopenharmony_ci /* Since 0.9.8 the user can ask for a couple of additional flags */ 179853a5a1b3Sopenharmony_ci 179953a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &no_remap) < 0 || 180053a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &no_remix) < 0 || 180153a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_format) < 0 || 180253a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_rate) < 0 || 180353a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_channels) < 0 || 180453a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &no_move) < 0 || 180553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &variable_rate) < 0) { 180653a5a1b3Sopenharmony_ci 180753a5a1b3Sopenharmony_ci protocol_error(c); 180853a5a1b3Sopenharmony_ci goto finish; 180953a5a1b3Sopenharmony_ci } 181053a5a1b3Sopenharmony_ci } 181153a5a1b3Sopenharmony_ci 181253a5a1b3Sopenharmony_ci if (c->version >= 13) { 181353a5a1b3Sopenharmony_ci 181453a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &muted) < 0 || 181553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &adjust_latency) < 0 || 181653a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, p) < 0) { 181753a5a1b3Sopenharmony_ci 181853a5a1b3Sopenharmony_ci protocol_error(c); 181953a5a1b3Sopenharmony_ci goto finish; 182053a5a1b3Sopenharmony_ci } 182153a5a1b3Sopenharmony_ci } 182253a5a1b3Sopenharmony_ci 182353a5a1b3Sopenharmony_ci if (c->version >= 14) { 182453a5a1b3Sopenharmony_ci 182553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &volume_set) < 0 || 182653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &early_requests) < 0) { 182753a5a1b3Sopenharmony_ci 182853a5a1b3Sopenharmony_ci protocol_error(c); 182953a5a1b3Sopenharmony_ci goto finish; 183053a5a1b3Sopenharmony_ci } 183153a5a1b3Sopenharmony_ci } 183253a5a1b3Sopenharmony_ci 183353a5a1b3Sopenharmony_ci if (c->version >= 15) { 183453a5a1b3Sopenharmony_ci 183553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &muted_set) < 0 || 183653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 || 183753a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) { 183853a5a1b3Sopenharmony_ci 183953a5a1b3Sopenharmony_ci protocol_error(c); 184053a5a1b3Sopenharmony_ci goto finish; 184153a5a1b3Sopenharmony_ci } 184253a5a1b3Sopenharmony_ci } 184353a5a1b3Sopenharmony_ci 184453a5a1b3Sopenharmony_ci if (c->version >= 17) { 184553a5a1b3Sopenharmony_ci 184653a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &relative_volume) < 0) { 184753a5a1b3Sopenharmony_ci 184853a5a1b3Sopenharmony_ci protocol_error(c); 184953a5a1b3Sopenharmony_ci goto finish; 185053a5a1b3Sopenharmony_ci } 185153a5a1b3Sopenharmony_ci } 185253a5a1b3Sopenharmony_ci 185353a5a1b3Sopenharmony_ci if (c->version >= 18) { 185453a5a1b3Sopenharmony_ci 185553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &passthrough) < 0 ) { 185653a5a1b3Sopenharmony_ci protocol_error(c); 185753a5a1b3Sopenharmony_ci goto finish; 185853a5a1b3Sopenharmony_ci } 185953a5a1b3Sopenharmony_ci } 186053a5a1b3Sopenharmony_ci 186153a5a1b3Sopenharmony_ci if (c->version >= 21) { 186253a5a1b3Sopenharmony_ci 186353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu8(t, &n_formats) < 0) { 186453a5a1b3Sopenharmony_ci protocol_error(c); 186553a5a1b3Sopenharmony_ci goto finish; 186653a5a1b3Sopenharmony_ci } 186753a5a1b3Sopenharmony_ci 186853a5a1b3Sopenharmony_ci if (n_formats) 186953a5a1b3Sopenharmony_ci formats = pa_idxset_new(NULL, NULL); 187053a5a1b3Sopenharmony_ci 187153a5a1b3Sopenharmony_ci for (i = 0; i < n_formats; i++) { 187253a5a1b3Sopenharmony_ci format = pa_format_info_new(); 187353a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, format) < 0) { 187453a5a1b3Sopenharmony_ci protocol_error(c); 187553a5a1b3Sopenharmony_ci goto finish; 187653a5a1b3Sopenharmony_ci } 187753a5a1b3Sopenharmony_ci pa_idxset_put(formats, format, NULL); 187853a5a1b3Sopenharmony_ci } 187953a5a1b3Sopenharmony_ci } 188053a5a1b3Sopenharmony_ci 188153a5a1b3Sopenharmony_ci if (n_formats == 0) { 188253a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish); 188353a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID, finish); 188453a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish); 188553a5a1b3Sopenharmony_ci } else { 188653a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(format, formats, i) { 188753a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish); 188853a5a1b3Sopenharmony_ci } 188953a5a1b3Sopenharmony_ci } 189053a5a1b3Sopenharmony_ci 189153a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 189253a5a1b3Sopenharmony_ci protocol_error(c); 189353a5a1b3Sopenharmony_ci goto finish; 189453a5a1b3Sopenharmony_ci } 189553a5a1b3Sopenharmony_ci 189653a5a1b3Sopenharmony_ci if (sink_index != PA_INVALID_INDEX) { 189753a5a1b3Sopenharmony_ci 189853a5a1b3Sopenharmony_ci if (!(sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index))) { 189953a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 190053a5a1b3Sopenharmony_ci goto finish; 190153a5a1b3Sopenharmony_ci } 190253a5a1b3Sopenharmony_ci 190353a5a1b3Sopenharmony_ci } else if (sink_name) { 190453a5a1b3Sopenharmony_ci 190553a5a1b3Sopenharmony_ci if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) { 190653a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 190753a5a1b3Sopenharmony_ci goto finish; 190853a5a1b3Sopenharmony_ci } 190953a5a1b3Sopenharmony_ci } 191053a5a1b3Sopenharmony_ci 191153a5a1b3Sopenharmony_ci flags = 191253a5a1b3Sopenharmony_ci (corked ? PA_SINK_INPUT_START_CORKED : 0) | 191353a5a1b3Sopenharmony_ci (no_remap ? PA_SINK_INPUT_NO_REMAP : 0) | 191453a5a1b3Sopenharmony_ci (no_remix ? PA_SINK_INPUT_NO_REMIX : 0) | 191553a5a1b3Sopenharmony_ci (fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0) | 191653a5a1b3Sopenharmony_ci (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) | 191753a5a1b3Sopenharmony_ci (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | 191853a5a1b3Sopenharmony_ci (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | 191953a5a1b3Sopenharmony_ci (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | 192053a5a1b3Sopenharmony_ci (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | 192153a5a1b3Sopenharmony_ci (fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND : 0) | 192253a5a1b3Sopenharmony_ci (passthrough ? PA_SINK_INPUT_PASSTHROUGH : 0); 192353a5a1b3Sopenharmony_ci 192453a5a1b3Sopenharmony_ci /* Only since protocol version 15 there's a separate muted_set 192553a5a1b3Sopenharmony_ci * flag. For older versions we synthesize it here */ 192653a5a1b3Sopenharmony_ci muted_set = muted_set || muted; 192753a5a1b3Sopenharmony_ci 192853a5a1b3Sopenharmony_ci s = playback_stream_new(c, sink, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, syncid, &missing, &ret); 192953a5a1b3Sopenharmony_ci /* We no longer own the formats idxset */ 193053a5a1b3Sopenharmony_ci formats = NULL; 193153a5a1b3Sopenharmony_ci 193253a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish); 193353a5a1b3Sopenharmony_ci 193453a5a1b3Sopenharmony_ci reply = reply_new(tag); 193553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->index); 193653a5a1b3Sopenharmony_ci pa_assert(s->sink_input); 193753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->sink_input->index); 193853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, missing); 193953a5a1b3Sopenharmony_ci 194053a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 194153a5a1b3Sopenharmony_ci pa_log("initial request is %u", missing); 194253a5a1b3Sopenharmony_ci#endif 194353a5a1b3Sopenharmony_ci 194453a5a1b3Sopenharmony_ci if (c->version >= 9) { 194553a5a1b3Sopenharmony_ci /* Since 0.9.0 we support sending the buffer metrics back to the client */ 194653a5a1b3Sopenharmony_ci 194753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength); 194853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength); 194953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf); 195053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq); 195153a5a1b3Sopenharmony_ci } 195253a5a1b3Sopenharmony_ci 195353a5a1b3Sopenharmony_ci if (c->version >= 12) { 195453a5a1b3Sopenharmony_ci /* Since 0.9.8 we support sending the chosen sample 195553a5a1b3Sopenharmony_ci * spec/channel map/device/suspend status back to the 195653a5a1b3Sopenharmony_ci * client */ 195753a5a1b3Sopenharmony_ci 195853a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(reply, &ss); 195953a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(reply, &map); 196053a5a1b3Sopenharmony_ci 196153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->sink_input->sink->index); 196253a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, s->sink_input->sink->name); 196353a5a1b3Sopenharmony_ci 196453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, s->sink_input->sink->state == PA_SINK_SUSPENDED); 196553a5a1b3Sopenharmony_ci } 196653a5a1b3Sopenharmony_ci 196753a5a1b3Sopenharmony_ci if (c->version >= 13) 196853a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, s->configured_sink_latency); 196953a5a1b3Sopenharmony_ci 197053a5a1b3Sopenharmony_ci if (c->version >= 21) { 197153a5a1b3Sopenharmony_ci /* Send back the format we negotiated */ 197253a5a1b3Sopenharmony_ci if (s->sink_input->format) 197353a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(reply, s->sink_input->format); 197453a5a1b3Sopenharmony_ci else { 197553a5a1b3Sopenharmony_ci pa_format_info *f = pa_format_info_new(); 197653a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(reply, f); 197753a5a1b3Sopenharmony_ci pa_format_info_free(f); 197853a5a1b3Sopenharmony_ci } 197953a5a1b3Sopenharmony_ci } 198053a5a1b3Sopenharmony_ci 198153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 198253a5a1b3Sopenharmony_ci 198353a5a1b3Sopenharmony_cifinish: 198453a5a1b3Sopenharmony_ci if (p) 198553a5a1b3Sopenharmony_ci pa_proplist_free(p); 198653a5a1b3Sopenharmony_ci if (formats) 198753a5a1b3Sopenharmony_ci pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free); 198853a5a1b3Sopenharmony_ci} 198953a5a1b3Sopenharmony_ci 199053a5a1b3Sopenharmony_cistatic void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 199153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 199253a5a1b3Sopenharmony_ci uint32_t channel; 199353a5a1b3Sopenharmony_ci 199453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 199553a5a1b3Sopenharmony_ci pa_assert(t); 199653a5a1b3Sopenharmony_ci 199753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 199853a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 199953a5a1b3Sopenharmony_ci protocol_error(c); 200053a5a1b3Sopenharmony_ci return; 200153a5a1b3Sopenharmony_ci } 200253a5a1b3Sopenharmony_ci 200353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 200453a5a1b3Sopenharmony_ci 200553a5a1b3Sopenharmony_ci switch (command) { 200653a5a1b3Sopenharmony_ci 200753a5a1b3Sopenharmony_ci case PA_COMMAND_DELETE_PLAYBACK_STREAM: { 200853a5a1b3Sopenharmony_ci playback_stream *s; 200953a5a1b3Sopenharmony_ci if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !playback_stream_isinstance(s)) { 201053a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 201153a5a1b3Sopenharmony_ci return; 201253a5a1b3Sopenharmony_ci } 201353a5a1b3Sopenharmony_ci 201453a5a1b3Sopenharmony_ci playback_stream_unlink(s); 201553a5a1b3Sopenharmony_ci break; 201653a5a1b3Sopenharmony_ci } 201753a5a1b3Sopenharmony_ci 201853a5a1b3Sopenharmony_ci case PA_COMMAND_DELETE_RECORD_STREAM: { 201953a5a1b3Sopenharmony_ci record_stream *s; 202053a5a1b3Sopenharmony_ci if (!(s = pa_idxset_get_by_index(c->record_streams, channel))) { 202153a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 202253a5a1b3Sopenharmony_ci return; 202353a5a1b3Sopenharmony_ci } 202453a5a1b3Sopenharmony_ci 202553a5a1b3Sopenharmony_ci record_stream_unlink(s); 202653a5a1b3Sopenharmony_ci break; 202753a5a1b3Sopenharmony_ci } 202853a5a1b3Sopenharmony_ci 202953a5a1b3Sopenharmony_ci case PA_COMMAND_DELETE_UPLOAD_STREAM: { 203053a5a1b3Sopenharmony_ci upload_stream *s; 203153a5a1b3Sopenharmony_ci 203253a5a1b3Sopenharmony_ci if (!(s = pa_idxset_get_by_index(c->output_streams, channel)) || !upload_stream_isinstance(s)) { 203353a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 203453a5a1b3Sopenharmony_ci return; 203553a5a1b3Sopenharmony_ci } 203653a5a1b3Sopenharmony_ci 203753a5a1b3Sopenharmony_ci upload_stream_unlink(s); 203853a5a1b3Sopenharmony_ci break; 203953a5a1b3Sopenharmony_ci } 204053a5a1b3Sopenharmony_ci 204153a5a1b3Sopenharmony_ci default: 204253a5a1b3Sopenharmony_ci pa_assert_not_reached(); 204353a5a1b3Sopenharmony_ci } 204453a5a1b3Sopenharmony_ci 204553a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 204653a5a1b3Sopenharmony_ci} 204753a5a1b3Sopenharmony_ci 204853a5a1b3Sopenharmony_cistatic void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 204953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 205053a5a1b3Sopenharmony_ci record_stream *s; 205153a5a1b3Sopenharmony_ci pa_buffer_attr attr; 205253a5a1b3Sopenharmony_ci uint32_t source_index; 205353a5a1b3Sopenharmony_ci const char *name = NULL, *source_name; 205453a5a1b3Sopenharmony_ci pa_sample_spec ss; 205553a5a1b3Sopenharmony_ci pa_channel_map map; 205653a5a1b3Sopenharmony_ci pa_tagstruct *reply; 205753a5a1b3Sopenharmony_ci pa_source *source = NULL; 205853a5a1b3Sopenharmony_ci pa_cvolume volume; 205953a5a1b3Sopenharmony_ci bool 206053a5a1b3Sopenharmony_ci corked = false, 206153a5a1b3Sopenharmony_ci no_remap = false, 206253a5a1b3Sopenharmony_ci no_remix = false, 206353a5a1b3Sopenharmony_ci fix_format = false, 206453a5a1b3Sopenharmony_ci fix_rate = false, 206553a5a1b3Sopenharmony_ci fix_channels = false, 206653a5a1b3Sopenharmony_ci no_move = false, 206753a5a1b3Sopenharmony_ci variable_rate = false, 206853a5a1b3Sopenharmony_ci muted = false, 206953a5a1b3Sopenharmony_ci adjust_latency = false, 207053a5a1b3Sopenharmony_ci peak_detect = false, 207153a5a1b3Sopenharmony_ci early_requests = false, 207253a5a1b3Sopenharmony_ci dont_inhibit_auto_suspend = false, 207353a5a1b3Sopenharmony_ci volume_set = false, 207453a5a1b3Sopenharmony_ci muted_set = false, 207553a5a1b3Sopenharmony_ci fail_on_suspend = false, 207653a5a1b3Sopenharmony_ci relative_volume = false, 207753a5a1b3Sopenharmony_ci passthrough = false; 207853a5a1b3Sopenharmony_ci 207953a5a1b3Sopenharmony_ci pa_source_output_flags_t flags = 0; 208053a5a1b3Sopenharmony_ci pa_proplist *p = NULL; 208153a5a1b3Sopenharmony_ci uint32_t direct_on_input_idx = PA_INVALID_INDEX; 208253a5a1b3Sopenharmony_ci pa_sink_input *direct_on_input = NULL; 208353a5a1b3Sopenharmony_ci int ret = PA_ERR_INVALID; 208453a5a1b3Sopenharmony_ci uint8_t n_formats = 0; 208553a5a1b3Sopenharmony_ci pa_format_info *format; 208653a5a1b3Sopenharmony_ci pa_idxset *formats = NULL; 208753a5a1b3Sopenharmony_ci uint32_t i; 208853a5a1b3Sopenharmony_ci 208953a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 209053a5a1b3Sopenharmony_ci pa_assert(t); 209153a5a1b3Sopenharmony_ci 209253a5a1b3Sopenharmony_ci memset(&attr, 0, sizeof(attr)); 209353a5a1b3Sopenharmony_ci 209453a5a1b3Sopenharmony_ci if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) || 209553a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &ss) < 0 || 209653a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &map) < 0 || 209753a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &source_index) < 0 || 209853a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &source_name) < 0 || 209953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &attr.maxlength) < 0 || 210053a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &corked) < 0 || 210153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &attr.fragsize) < 0) { 210253a5a1b3Sopenharmony_ci 210353a5a1b3Sopenharmony_ci protocol_error(c); 210453a5a1b3Sopenharmony_ci goto finish; 210553a5a1b3Sopenharmony_ci } 210653a5a1b3Sopenharmony_ci 210753a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, c->authorized, tag, PA_ERR_ACCESS, finish); 210853a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, !source_name || pa_namereg_is_valid_name_or_wildcard(source_name, PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID, finish); 210953a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID, finish); 211053a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID, finish); 211153a5a1b3Sopenharmony_ci 211253a5a1b3Sopenharmony_ci p = pa_proplist_new(); 211353a5a1b3Sopenharmony_ci 211453a5a1b3Sopenharmony_ci if (name) 211553a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name); 211653a5a1b3Sopenharmony_ci 211753a5a1b3Sopenharmony_ci if (c->version >= 12) { 211853a5a1b3Sopenharmony_ci /* Since 0.9.8 the user can ask for a couple of additional flags */ 211953a5a1b3Sopenharmony_ci 212053a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &no_remap) < 0 || 212153a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &no_remix) < 0 || 212253a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_format) < 0 || 212353a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_rate) < 0 || 212453a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fix_channels) < 0 || 212553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &no_move) < 0 || 212653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &variable_rate) < 0) { 212753a5a1b3Sopenharmony_ci 212853a5a1b3Sopenharmony_ci protocol_error(c); 212953a5a1b3Sopenharmony_ci goto finish; 213053a5a1b3Sopenharmony_ci } 213153a5a1b3Sopenharmony_ci } 213253a5a1b3Sopenharmony_ci 213353a5a1b3Sopenharmony_ci if (c->version >= 13) { 213453a5a1b3Sopenharmony_ci 213553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 || 213653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &adjust_latency) < 0 || 213753a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, p) < 0 || 213853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &direct_on_input_idx) < 0) { 213953a5a1b3Sopenharmony_ci 214053a5a1b3Sopenharmony_ci protocol_error(c); 214153a5a1b3Sopenharmony_ci goto finish; 214253a5a1b3Sopenharmony_ci } 214353a5a1b3Sopenharmony_ci } 214453a5a1b3Sopenharmony_ci 214553a5a1b3Sopenharmony_ci if (c->version >= 14) { 214653a5a1b3Sopenharmony_ci 214753a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &early_requests) < 0) { 214853a5a1b3Sopenharmony_ci protocol_error(c); 214953a5a1b3Sopenharmony_ci goto finish; 215053a5a1b3Sopenharmony_ci } 215153a5a1b3Sopenharmony_ci } 215253a5a1b3Sopenharmony_ci 215353a5a1b3Sopenharmony_ci if (c->version >= 15) { 215453a5a1b3Sopenharmony_ci 215553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0 || 215653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &fail_on_suspend) < 0) { 215753a5a1b3Sopenharmony_ci 215853a5a1b3Sopenharmony_ci protocol_error(c); 215953a5a1b3Sopenharmony_ci goto finish; 216053a5a1b3Sopenharmony_ci } 216153a5a1b3Sopenharmony_ci } 216253a5a1b3Sopenharmony_ci 216353a5a1b3Sopenharmony_ci if (c->version >= 22) { 216453a5a1b3Sopenharmony_ci /* For newer client versions (with per-source-output volumes), we try 216553a5a1b3Sopenharmony_ci * to make the behaviour for playback and record streams the same. */ 216653a5a1b3Sopenharmony_ci volume_set = true; 216753a5a1b3Sopenharmony_ci 216853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu8(t, &n_formats) < 0) { 216953a5a1b3Sopenharmony_ci protocol_error(c); 217053a5a1b3Sopenharmony_ci goto finish; 217153a5a1b3Sopenharmony_ci } 217253a5a1b3Sopenharmony_ci 217353a5a1b3Sopenharmony_ci if (n_formats) 217453a5a1b3Sopenharmony_ci formats = pa_idxset_new(NULL, NULL); 217553a5a1b3Sopenharmony_ci 217653a5a1b3Sopenharmony_ci for (i = 0; i < n_formats; i++) { 217753a5a1b3Sopenharmony_ci format = pa_format_info_new(); 217853a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, format) < 0) { 217953a5a1b3Sopenharmony_ci protocol_error(c); 218053a5a1b3Sopenharmony_ci goto finish; 218153a5a1b3Sopenharmony_ci } 218253a5a1b3Sopenharmony_ci pa_idxset_put(formats, format, NULL); 218353a5a1b3Sopenharmony_ci } 218453a5a1b3Sopenharmony_ci 218553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_cvolume(t, &volume) < 0 || 218653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &muted) < 0 || 218753a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &volume_set) < 0 || 218853a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &muted_set) < 0 || 218953a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &relative_volume) < 0 || 219053a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &passthrough) < 0) { 219153a5a1b3Sopenharmony_ci 219253a5a1b3Sopenharmony_ci protocol_error(c); 219353a5a1b3Sopenharmony_ci goto finish; 219453a5a1b3Sopenharmony_ci } 219553a5a1b3Sopenharmony_ci 219653a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID, finish); 219753a5a1b3Sopenharmony_ci } 219853a5a1b3Sopenharmony_ci 219953a5a1b3Sopenharmony_ci if (n_formats == 0) { 220053a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID, finish); 220153a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID, finish); 220253a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, c->version < 22 || (volume.channels == ss.channels), tag, PA_ERR_INVALID, finish); 220353a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID, finish); 220453a5a1b3Sopenharmony_ci } else { 220553a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(format, formats, i) { 220653a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, pa_format_info_valid(format), tag, PA_ERR_INVALID, finish); 220753a5a1b3Sopenharmony_ci } 220853a5a1b3Sopenharmony_ci } 220953a5a1b3Sopenharmony_ci 221053a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 221153a5a1b3Sopenharmony_ci protocol_error(c); 221253a5a1b3Sopenharmony_ci goto finish; 221353a5a1b3Sopenharmony_ci } 221453a5a1b3Sopenharmony_ci 221553a5a1b3Sopenharmony_ci if (source_index != PA_INVALID_INDEX) { 221653a5a1b3Sopenharmony_ci 221753a5a1b3Sopenharmony_ci if (!(source = pa_idxset_get_by_index(c->protocol->core->sources, source_index))) { 221853a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 221953a5a1b3Sopenharmony_ci goto finish; 222053a5a1b3Sopenharmony_ci } 222153a5a1b3Sopenharmony_ci 222253a5a1b3Sopenharmony_ci } else if (source_name) { 222353a5a1b3Sopenharmony_ci 222453a5a1b3Sopenharmony_ci if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) { 222553a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 222653a5a1b3Sopenharmony_ci goto finish; 222753a5a1b3Sopenharmony_ci } 222853a5a1b3Sopenharmony_ci } 222953a5a1b3Sopenharmony_ci 223053a5a1b3Sopenharmony_ci if (direct_on_input_idx != PA_INVALID_INDEX) { 223153a5a1b3Sopenharmony_ci 223253a5a1b3Sopenharmony_ci if (!(direct_on_input = pa_idxset_get_by_index(c->protocol->core->sink_inputs, direct_on_input_idx))) { 223353a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 223453a5a1b3Sopenharmony_ci goto finish; 223553a5a1b3Sopenharmony_ci } 223653a5a1b3Sopenharmony_ci } 223753a5a1b3Sopenharmony_ci 223853a5a1b3Sopenharmony_ci flags = 223953a5a1b3Sopenharmony_ci (corked ? PA_SOURCE_OUTPUT_START_CORKED : 0) | 224053a5a1b3Sopenharmony_ci (no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0) | 224153a5a1b3Sopenharmony_ci (no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0) | 224253a5a1b3Sopenharmony_ci (fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0) | 224353a5a1b3Sopenharmony_ci (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) | 224453a5a1b3Sopenharmony_ci (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | 224553a5a1b3Sopenharmony_ci (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | 224653a5a1b3Sopenharmony_ci (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | 224753a5a1b3Sopenharmony_ci (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) | 224853a5a1b3Sopenharmony_ci (fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND|PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0) | 224953a5a1b3Sopenharmony_ci (passthrough ? PA_SOURCE_OUTPUT_PASSTHROUGH : 0); 225053a5a1b3Sopenharmony_ci 225153a5a1b3Sopenharmony_ci s = record_stream_new(c, source, &ss, &map, formats, &attr, volume_set ? &volume : NULL, muted, muted_set, flags, p, adjust_latency, early_requests, relative_volume, peak_detect, direct_on_input, &ret); 225253a5a1b3Sopenharmony_ci /* We no longer own the formats idxset */ 225353a5a1b3Sopenharmony_ci formats = NULL; 225453a5a1b3Sopenharmony_ci 225553a5a1b3Sopenharmony_ci CHECK_VALIDITY_GOTO(c->pstream, s, tag, ret, finish); 225653a5a1b3Sopenharmony_ci 225753a5a1b3Sopenharmony_ci reply = reply_new(tag); 225853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->index); 225953a5a1b3Sopenharmony_ci pa_assert(s->source_output); 226053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->source_output->index); 226153a5a1b3Sopenharmony_ci 226253a5a1b3Sopenharmony_ci if (c->version >= 9) { 226353a5a1b3Sopenharmony_ci /* Since 0.9 we support sending the buffer metrics back to the client */ 226453a5a1b3Sopenharmony_ci 226553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength); 226653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize); 226753a5a1b3Sopenharmony_ci } 226853a5a1b3Sopenharmony_ci 226953a5a1b3Sopenharmony_ci if (c->version >= 12) { 227053a5a1b3Sopenharmony_ci /* Since 0.9.8 we support sending the chosen sample 227153a5a1b3Sopenharmony_ci * spec/channel map/device/suspend status back to the 227253a5a1b3Sopenharmony_ci * client */ 227353a5a1b3Sopenharmony_ci 227453a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(reply, &ss); 227553a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(reply, &map); 227653a5a1b3Sopenharmony_ci 227753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->source_output->source->index); 227853a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, s->source_output->source->name); 227953a5a1b3Sopenharmony_ci 228053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, s->source_output->source->state == PA_SOURCE_SUSPENDED); 228153a5a1b3Sopenharmony_ci } 228253a5a1b3Sopenharmony_ci 228353a5a1b3Sopenharmony_ci if (c->version >= 13) 228453a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, s->configured_source_latency); 228553a5a1b3Sopenharmony_ci 228653a5a1b3Sopenharmony_ci if (c->version >= 22) { 228753a5a1b3Sopenharmony_ci /* Send back the format we negotiated */ 228853a5a1b3Sopenharmony_ci if (s->source_output->format) 228953a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(reply, s->source_output->format); 229053a5a1b3Sopenharmony_ci else { 229153a5a1b3Sopenharmony_ci pa_format_info *f = pa_format_info_new(); 229253a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(reply, f); 229353a5a1b3Sopenharmony_ci pa_format_info_free(f); 229453a5a1b3Sopenharmony_ci } 229553a5a1b3Sopenharmony_ci } 229653a5a1b3Sopenharmony_ci 229753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 229853a5a1b3Sopenharmony_ci 229953a5a1b3Sopenharmony_cifinish: 230053a5a1b3Sopenharmony_ci if (p) 230153a5a1b3Sopenharmony_ci pa_proplist_free(p); 230253a5a1b3Sopenharmony_ci if (formats) 230353a5a1b3Sopenharmony_ci pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free); 230453a5a1b3Sopenharmony_ci} 230553a5a1b3Sopenharmony_ci 230653a5a1b3Sopenharmony_cistatic void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 230753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 230853a5a1b3Sopenharmony_ci int ret; 230953a5a1b3Sopenharmony_ci 231053a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 231153a5a1b3Sopenharmony_ci pa_assert(t); 231253a5a1b3Sopenharmony_ci 231353a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 231453a5a1b3Sopenharmony_ci protocol_error(c); 231553a5a1b3Sopenharmony_ci return; 231653a5a1b3Sopenharmony_ci } 231753a5a1b3Sopenharmony_ci 231853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 231953a5a1b3Sopenharmony_ci ret = pa_core_exit(c->protocol->core, false, 0); 232053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS); 232153a5a1b3Sopenharmony_ci 232253a5a1b3Sopenharmony_ci pa_log_debug("Client %s asks us to terminate.", pa_strnull(pa_proplist_gets(c->client->proplist, 232353a5a1b3Sopenharmony_ci PA_PROP_APPLICATION_PROCESS_BINARY))); 232453a5a1b3Sopenharmony_ci 232553a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ 232653a5a1b3Sopenharmony_ci} 232753a5a1b3Sopenharmony_ci 232853a5a1b3Sopenharmony_cistatic void setup_srbchannel(pa_native_connection *c, pa_mem_type_t shm_type) { 232953a5a1b3Sopenharmony_ci pa_srbchannel_template srbt; 233053a5a1b3Sopenharmony_ci pa_srbchannel *srb; 233153a5a1b3Sopenharmony_ci pa_memchunk mc; 233253a5a1b3Sopenharmony_ci pa_tagstruct *t; 233353a5a1b3Sopenharmony_ci int fdlist[2]; 233453a5a1b3Sopenharmony_ci pa_log_info("start setup_srbchannel, shm_type: %d", shm_type); 233553a5a1b3Sopenharmony_ci#ifndef HAVE_CREDS 233653a5a1b3Sopenharmony_ci pa_log_debug("Disabling srbchannel, reason: No fd passing support"); 233753a5a1b3Sopenharmony_ci return; 233853a5a1b3Sopenharmony_ci#endif 233953a5a1b3Sopenharmony_ci 234053a5a1b3Sopenharmony_ci if (!c->options->srbchannel) { 234153a5a1b3Sopenharmony_ci pa_log_debug("Disabling srbchannel, reason: Must be enabled by module parameter"); 234253a5a1b3Sopenharmony_ci return; 234353a5a1b3Sopenharmony_ci } 234453a5a1b3Sopenharmony_ci 234553a5a1b3Sopenharmony_ci if (c->version < 30) { 234653a5a1b3Sopenharmony_ci pa_log_debug("Disabling srbchannel, reason: Protocol too old"); 234753a5a1b3Sopenharmony_ci return; 234853a5a1b3Sopenharmony_ci } 234953a5a1b3Sopenharmony_ci 235053a5a1b3Sopenharmony_ci if (!pa_pstream_get_shm(c->pstream)) { 235153a5a1b3Sopenharmony_ci pa_log_debug("Disabling srbchannel, reason: No SHM support"); 235253a5a1b3Sopenharmony_ci return; 235353a5a1b3Sopenharmony_ci } 235453a5a1b3Sopenharmony_ci 235553a5a1b3Sopenharmony_ci if (c->rw_mempool) { 235653a5a1b3Sopenharmony_ci pa_log_debug("Ignoring srbchannel setup, reason: received COMMAND_AUTH " 235753a5a1b3Sopenharmony_ci "more than once"); 235853a5a1b3Sopenharmony_ci return; 235953a5a1b3Sopenharmony_ci } 236053a5a1b3Sopenharmony_ci 236153a5a1b3Sopenharmony_ci if (!(c->rw_mempool = pa_mempool_new(shm_type, c->protocol->core->shm_size, true))) { 236253a5a1b3Sopenharmony_ci pa_log_debug("Disabling srbchannel, reason: Failed to allocate shared " 236353a5a1b3Sopenharmony_ci "writable memory pool."); 236453a5a1b3Sopenharmony_ci return; 236553a5a1b3Sopenharmony_ci } 236653a5a1b3Sopenharmony_ci 236753a5a1b3Sopenharmony_ci if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) { 236853a5a1b3Sopenharmony_ci const char *reason; 236953a5a1b3Sopenharmony_ci if (pa_pstream_register_memfd_mempool(c->pstream, c->rw_mempool, &reason)) { 237053a5a1b3Sopenharmony_ci pa_log_warn("Disabling srbchannel, reason: Failed to register memfd mempool: %s", reason); 237153a5a1b3Sopenharmony_ci goto fail; 237253a5a1b3Sopenharmony_ci } 237353a5a1b3Sopenharmony_ci } 237453a5a1b3Sopenharmony_ci pa_mempool_set_is_remote_writable(c->rw_mempool, true); 237553a5a1b3Sopenharmony_ci 237653a5a1b3Sopenharmony_ci srb = pa_srbchannel_new(c->protocol->core->mainloop, c->rw_mempool); 237753a5a1b3Sopenharmony_ci if (!srb) { 237853a5a1b3Sopenharmony_ci pa_log_debug("Failed to create srbchannel"); 237953a5a1b3Sopenharmony_ci goto fail; 238053a5a1b3Sopenharmony_ci } 238153a5a1b3Sopenharmony_ci pa_log_debug("Enabling srbchannel..."); 238253a5a1b3Sopenharmony_ci pa_srbchannel_export(srb, &srbt); 238353a5a1b3Sopenharmony_ci 238453a5a1b3Sopenharmony_ci /* Send enable command to client */ 238553a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 238653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_ENABLE_SRBCHANNEL); 238753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (size_t) srb); /* tag */ 238853a5a1b3Sopenharmony_ci fdlist[0] = srbt.readfd; 238953a5a1b3Sopenharmony_ci fdlist[1] = srbt.writefd; 239053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct_with_fds(c->pstream, t, 2, fdlist, false); 239153a5a1b3Sopenharmony_ci 239253a5a1b3Sopenharmony_ci /* Send ringbuffer memblock to client */ 239353a5a1b3Sopenharmony_ci mc.memblock = srbt.memblock; 239453a5a1b3Sopenharmony_ci mc.index = 0; 239553a5a1b3Sopenharmony_ci mc.length = pa_memblock_get_length(srbt.memblock); 239653a5a1b3Sopenharmony_ci pa_pstream_send_memblock(c->pstream, 0, 0, 0, &mc); 239753a5a1b3Sopenharmony_ci 239853a5a1b3Sopenharmony_ci c->srbpending = srb; 239953a5a1b3Sopenharmony_ci return; 240053a5a1b3Sopenharmony_ci 240153a5a1b3Sopenharmony_cifail: 240253a5a1b3Sopenharmony_ci if (c->rw_mempool) { 240353a5a1b3Sopenharmony_ci pa_mempool_unref(c->rw_mempool); 240453a5a1b3Sopenharmony_ci c->rw_mempool = NULL; 240553a5a1b3Sopenharmony_ci } 240653a5a1b3Sopenharmony_ci} 240753a5a1b3Sopenharmony_ci 240853a5a1b3Sopenharmony_cistatic void command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 240953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 241053a5a1b3Sopenharmony_ci 241153a5a1b3Sopenharmony_ci if (tag != (uint32_t) (size_t) c->srbpending) { 241253a5a1b3Sopenharmony_ci protocol_error(c); 241353a5a1b3Sopenharmony_ci return; 241453a5a1b3Sopenharmony_ci } 241553a5a1b3Sopenharmony_ci 241653a5a1b3Sopenharmony_ci pa_log_debug("Client enabled srbchannel."); 241753a5a1b3Sopenharmony_ci pa_pstream_set_srbchannel(c->pstream, c->srbpending); 241853a5a1b3Sopenharmony_ci c->srbpending = NULL; 241953a5a1b3Sopenharmony_ci} 242053a5a1b3Sopenharmony_ci 242153a5a1b3Sopenharmony_cistatic void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 242253a5a1b3Sopenharmony_ci pa_log_info("start command_authd"); 242353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 242453a5a1b3Sopenharmony_ci const void*cookie; 242553a5a1b3Sopenharmony_ci bool memfd_on_remote = false, do_memfd = false; 242653a5a1b3Sopenharmony_ci pa_tagstruct *reply; 242753a5a1b3Sopenharmony_ci pa_mem_type_t shm_type; 242853a5a1b3Sopenharmony_ci bool shm_on_remote = false, do_shm; 242953a5a1b3Sopenharmony_ci 243053a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 243153a5a1b3Sopenharmony_ci pa_assert(t); 243253a5a1b3Sopenharmony_ci 243353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &c->version) < 0 || 243453a5a1b3Sopenharmony_ci pa_tagstruct_get_arbitrary(t, &cookie, PA_NATIVE_COOKIE_LENGTH) < 0 || 243553a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 243653a5a1b3Sopenharmony_ci protocol_error(c); 243753a5a1b3Sopenharmony_ci return; 243853a5a1b3Sopenharmony_ci } 243953a5a1b3Sopenharmony_ci 244053a5a1b3Sopenharmony_ci /* Minimum supported version */ 244153a5a1b3Sopenharmony_ci if (c->version < 8) { 244253a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_VERSION); 244353a5a1b3Sopenharmony_ci return; 244453a5a1b3Sopenharmony_ci } 244553a5a1b3Sopenharmony_ci 244653a5a1b3Sopenharmony_ci /* Starting with protocol version 13 the MSB of the version tag 244753a5a1b3Sopenharmony_ci reflects if shm is available for this pa_native_connection or 244853a5a1b3Sopenharmony_ci not. */ 244953a5a1b3Sopenharmony_ci if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 13) { 245053a5a1b3Sopenharmony_ci shm_on_remote = !!(c->version & PA_PROTOCOL_FLAG_SHM); 245153a5a1b3Sopenharmony_ci 245253a5a1b3Sopenharmony_ci /* Starting with protocol version 31, the second MSB of the version 245353a5a1b3Sopenharmony_ci * tag reflects whether memfd is supported on the other PA end. */ 245453a5a1b3Sopenharmony_ci if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 31) 245553a5a1b3Sopenharmony_ci memfd_on_remote = !!(c->version & PA_PROTOCOL_FLAG_MEMFD); 245653a5a1b3Sopenharmony_ci 245753a5a1b3Sopenharmony_ci /* Reserve the two most-significant _bytes_ of the version tag 245853a5a1b3Sopenharmony_ci * for flags. */ 245953a5a1b3Sopenharmony_ci c->version &= PA_PROTOCOL_VERSION_MASK; 246053a5a1b3Sopenharmony_ci } 246153a5a1b3Sopenharmony_ci 246253a5a1b3Sopenharmony_ci pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION); 246353a5a1b3Sopenharmony_ci 246453a5a1b3Sopenharmony_ci pa_proplist_setf(c->client->proplist, "native-protocol.version", "%u", c->version); 246553a5a1b3Sopenharmony_ci 246653a5a1b3Sopenharmony_ci if (!c->authorized) { 246753a5a1b3Sopenharmony_ci bool success = false; 246853a5a1b3Sopenharmony_ci 246953a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 247053a5a1b3Sopenharmony_ci const pa_creds *creds; 247153a5a1b3Sopenharmony_ci 247253a5a1b3Sopenharmony_ci if ((creds = pa_pdispatch_creds(pd))) { 247353a5a1b3Sopenharmony_ci if (creds->uid == getuid()) 247453a5a1b3Sopenharmony_ci success = true; 247553a5a1b3Sopenharmony_ci else if (c->options->auth_group) { 247653a5a1b3Sopenharmony_ci int r; 247753a5a1b3Sopenharmony_ci gid_t gid; 247853a5a1b3Sopenharmony_ci 247953a5a1b3Sopenharmony_ci if ((gid = pa_get_gid_of_group(c->options->auth_group)) == (gid_t) -1) 248053a5a1b3Sopenharmony_ci pa_log_warn("Failed to get GID of group '%s'", c->options->auth_group); 248153a5a1b3Sopenharmony_ci else if (gid == creds->gid) 248253a5a1b3Sopenharmony_ci success = true; 248353a5a1b3Sopenharmony_ci 248453a5a1b3Sopenharmony_ci if (!success) { 248553a5a1b3Sopenharmony_ci if ((r = pa_uid_in_group(creds->uid, c->options->auth_group)) < 0) 248653a5a1b3Sopenharmony_ci pa_log_warn("Failed to check group membership."); 248753a5a1b3Sopenharmony_ci else if (r > 0) 248853a5a1b3Sopenharmony_ci success = true; 248953a5a1b3Sopenharmony_ci } 249053a5a1b3Sopenharmony_ci } 249153a5a1b3Sopenharmony_ci 249253a5a1b3Sopenharmony_ci pa_log_debug("Got credentials: uid=%lu gid=%lu success=%i", 249353a5a1b3Sopenharmony_ci (unsigned long) creds->uid, 249453a5a1b3Sopenharmony_ci (unsigned long) creds->gid, 249553a5a1b3Sopenharmony_ci (int) success); 249653a5a1b3Sopenharmony_ci } 249753a5a1b3Sopenharmony_ci#endif 249853a5a1b3Sopenharmony_ci 249953a5a1b3Sopenharmony_ci if (!success && c->options->auth_cookie) { 250053a5a1b3Sopenharmony_ci const uint8_t *ac; 250153a5a1b3Sopenharmony_ci 250253a5a1b3Sopenharmony_ci if ((ac = pa_auth_cookie_read(c->options->auth_cookie, PA_NATIVE_COOKIE_LENGTH))) 250353a5a1b3Sopenharmony_ci if (memcmp(ac, cookie, PA_NATIVE_COOKIE_LENGTH) == 0) 250453a5a1b3Sopenharmony_ci success = true; 250553a5a1b3Sopenharmony_ci 250653a5a1b3Sopenharmony_ci /* All user process need to have the capability to connect and create pa stream, 250753a5a1b3Sopenharmony_ci * so all of them can get the right cookie through ipc, cookie file check is useless. 250853a5a1b3Sopenharmony_ci * We plan to use other way to protect some of the functions, instead of preventing 250953a5a1b3Sopenharmony_ci * connection. 251053a5a1b3Sopenharmony_ci */ 251153a5a1b3Sopenharmony_ci success = true; 251253a5a1b3Sopenharmony_ci } 251353a5a1b3Sopenharmony_ci 251453a5a1b3Sopenharmony_ci if (!success) { 251553a5a1b3Sopenharmony_ci pa_log_warn("Denied access to client with invalid authentication data."); 251653a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_ACCESS); 251753a5a1b3Sopenharmony_ci return; 251853a5a1b3Sopenharmony_ci } 251953a5a1b3Sopenharmony_ci 252053a5a1b3Sopenharmony_ci c->authorized = true; 252153a5a1b3Sopenharmony_ci if (c->auth_timeout_event) { 252253a5a1b3Sopenharmony_ci c->protocol->core->mainloop->time_free(c->auth_timeout_event); 252353a5a1b3Sopenharmony_ci c->auth_timeout_event = NULL; 252453a5a1b3Sopenharmony_ci } 252553a5a1b3Sopenharmony_ci } 252653a5a1b3Sopenharmony_ci 252753a5a1b3Sopenharmony_ci /* Enable shared memory and memfd support if possible */ 252853a5a1b3Sopenharmony_ci do_shm = 252953a5a1b3Sopenharmony_ci pa_mempool_is_shared(c->protocol->core->mempool) && 253053a5a1b3Sopenharmony_ci c->is_local; 253153a5a1b3Sopenharmony_ci 253253a5a1b3Sopenharmony_ci pa_log_debug("SHM possible: %s", pa_yes_no(do_shm)); 253353a5a1b3Sopenharmony_ci 253453a5a1b3Sopenharmony_ci if (do_shm) 253553a5a1b3Sopenharmony_ci if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) 253653a5a1b3Sopenharmony_ci do_shm = false; 253753a5a1b3Sopenharmony_ci 253853a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 253953a5a1b3Sopenharmony_ci if (do_shm) { 254053a5a1b3Sopenharmony_ci /* Only enable SHM if both sides are owned by the same 254153a5a1b3Sopenharmony_ci * user. This is a security measure because otherwise data 254253a5a1b3Sopenharmony_ci * private to the user might leak. */ 254353a5a1b3Sopenharmony_ci 254453a5a1b3Sopenharmony_ci const pa_creds *creds; 254553a5a1b3Sopenharmony_ci if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) 254653a5a1b3Sopenharmony_ci do_shm = false; 254753a5a1b3Sopenharmony_ci } 254853a5a1b3Sopenharmony_ci#endif 254953a5a1b3Sopenharmony_ci 255053a5a1b3Sopenharmony_ci pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); 255153a5a1b3Sopenharmony_ci pa_pstream_enable_shm(c->pstream, do_shm); 255253a5a1b3Sopenharmony_ci 255353a5a1b3Sopenharmony_ci /* Do not declare memfd support for 9.0 client libraries (protocol v31). 255453a5a1b3Sopenharmony_ci * 255553a5a1b3Sopenharmony_ci * Although they support memfd transport, such 9.0 clients has an iochannel 255653a5a1b3Sopenharmony_ci * bug that would break memfd audio if they're run in 32-bit mode over a 255753a5a1b3Sopenharmony_ci * 64-bit kernel. Thus influence them to use the POSIX shared memory model 255853a5a1b3Sopenharmony_ci * instead. Check commit 451d1d676237c81 for further details. */ 255953a5a1b3Sopenharmony_ci do_memfd = 256053a5a1b3Sopenharmony_ci c->version >= 32 && do_shm && pa_mempool_is_memfd_backed(c->protocol->core->mempool); 256153a5a1b3Sopenharmony_ci 256253a5a1b3Sopenharmony_ci shm_type = PA_MEM_TYPE_PRIVATE; 256353a5a1b3Sopenharmony_ci if (do_shm) { 256453a5a1b3Sopenharmony_ci if (do_memfd && memfd_on_remote) { 256553a5a1b3Sopenharmony_ci pa_pstream_enable_memfd(c->pstream); 256653a5a1b3Sopenharmony_ci shm_type = PA_MEM_TYPE_SHARED_MEMFD; 256753a5a1b3Sopenharmony_ci } else 256853a5a1b3Sopenharmony_ci shm_type = PA_MEM_TYPE_SHARED_POSIX; 256953a5a1b3Sopenharmony_ci 257053a5a1b3Sopenharmony_ci pa_log_info("Memfd possible: %s", pa_yes_no(pa_memfd_is_locally_supported())); 257153a5a1b3Sopenharmony_ci pa_log_info("Negotiated SHM type: %s", pa_mem_type_to_string(shm_type)); 257253a5a1b3Sopenharmony_ci } 257353a5a1b3Sopenharmony_ci 257453a5a1b3Sopenharmony_ci reply = reply_new(tag); 257553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_PROTOCOL_VERSION | (do_shm ? 0x80000000 : 0) | 257653a5a1b3Sopenharmony_ci (do_memfd ? 0x40000000 : 0)); 257753a5a1b3Sopenharmony_ci 257853a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 257953a5a1b3Sopenharmony_ci{ 258053a5a1b3Sopenharmony_ci /* SHM support is only enabled after both sides made sure they are the same user. */ 258153a5a1b3Sopenharmony_ci 258253a5a1b3Sopenharmony_ci pa_creds ucred; 258353a5a1b3Sopenharmony_ci 258453a5a1b3Sopenharmony_ci ucred.uid = getuid(); 258553a5a1b3Sopenharmony_ci ucred.gid = getgid(); 258653a5a1b3Sopenharmony_ci 258753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct_with_creds(c->pstream, reply, &ucred); 258853a5a1b3Sopenharmony_ci} 258953a5a1b3Sopenharmony_ci#else 259053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 259153a5a1b3Sopenharmony_ci#endif 259253a5a1b3Sopenharmony_ci 259353a5a1b3Sopenharmony_ci /* The client enables memfd transport on its pstream only after 259453a5a1b3Sopenharmony_ci * inspecting our version flags to see if we support memfds too. 259553a5a1b3Sopenharmony_ci * 259653a5a1b3Sopenharmony_ci * Thus register any pools after sending the server's version 259753a5a1b3Sopenharmony_ci * flags and _never_ before it. */ 259853a5a1b3Sopenharmony_ci if (shm_type == PA_MEM_TYPE_SHARED_MEMFD) { 259953a5a1b3Sopenharmony_ci const char *reason; 260053a5a1b3Sopenharmony_ci 260153a5a1b3Sopenharmony_ci if (pa_pstream_register_memfd_mempool(c->pstream, c->protocol->core->mempool, &reason)) 260253a5a1b3Sopenharmony_ci pa_log("Failed to register memfd mempool. Reason: %s", reason); 260353a5a1b3Sopenharmony_ci } 260453a5a1b3Sopenharmony_ci 260553a5a1b3Sopenharmony_ci setup_srbchannel(c, shm_type); 260653a5a1b3Sopenharmony_ci} 260753a5a1b3Sopenharmony_ci 260853a5a1b3Sopenharmony_cistatic void command_register_memfd_shmid(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 260953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 261053a5a1b3Sopenharmony_ci 261153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 261253a5a1b3Sopenharmony_ci pa_assert(t); 261353a5a1b3Sopenharmony_ci 261453a5a1b3Sopenharmony_ci if (pa_common_command_register_memfd_shmid(c->pstream, pd, c->version, command, t)) 261553a5a1b3Sopenharmony_ci protocol_error(c); 261653a5a1b3Sopenharmony_ci} 261753a5a1b3Sopenharmony_ci 261853a5a1b3Sopenharmony_cistatic void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 261953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 262053a5a1b3Sopenharmony_ci const char *name = NULL; 262153a5a1b3Sopenharmony_ci pa_proplist *p; 262253a5a1b3Sopenharmony_ci pa_tagstruct *reply; 262353a5a1b3Sopenharmony_ci 262453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 262553a5a1b3Sopenharmony_ci pa_assert(t); 262653a5a1b3Sopenharmony_ci 262753a5a1b3Sopenharmony_ci p = pa_proplist_new(); 262853a5a1b3Sopenharmony_ci 262953a5a1b3Sopenharmony_ci if ((c->version < 13 && pa_tagstruct_gets(t, &name) < 0) || 263053a5a1b3Sopenharmony_ci (c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) || 263153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 263253a5a1b3Sopenharmony_ci 263353a5a1b3Sopenharmony_ci protocol_error(c); 263453a5a1b3Sopenharmony_ci pa_proplist_free(p); 263553a5a1b3Sopenharmony_ci return; 263653a5a1b3Sopenharmony_ci } 263753a5a1b3Sopenharmony_ci 263853a5a1b3Sopenharmony_ci if (name) 263953a5a1b3Sopenharmony_ci if (pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name) < 0) { 264053a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 264153a5a1b3Sopenharmony_ci pa_proplist_free(p); 264253a5a1b3Sopenharmony_ci return; 264353a5a1b3Sopenharmony_ci } 264453a5a1b3Sopenharmony_ci 264553a5a1b3Sopenharmony_ci pa_client_update_proplist(c->client, PA_UPDATE_REPLACE, p); 264653a5a1b3Sopenharmony_ci pa_proplist_free(p); 264753a5a1b3Sopenharmony_ci 264853a5a1b3Sopenharmony_ci reply = reply_new(tag); 264953a5a1b3Sopenharmony_ci 265053a5a1b3Sopenharmony_ci if (c->version >= 13) 265153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, c->client->index); 265253a5a1b3Sopenharmony_ci 265353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 265453a5a1b3Sopenharmony_ci} 265553a5a1b3Sopenharmony_ci 265653a5a1b3Sopenharmony_cistatic void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 265753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 265853a5a1b3Sopenharmony_ci const char *name; 265953a5a1b3Sopenharmony_ci uint32_t idx = PA_IDXSET_INVALID; 266053a5a1b3Sopenharmony_ci 266153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 266253a5a1b3Sopenharmony_ci pa_assert(t); 266353a5a1b3Sopenharmony_ci 266453a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &name) < 0 || 266553a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 266653a5a1b3Sopenharmony_ci protocol_error(c); 266753a5a1b3Sopenharmony_ci return; 266853a5a1b3Sopenharmony_ci } 266953a5a1b3Sopenharmony_ci 267053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 267153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_LOOKUP_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); 267253a5a1b3Sopenharmony_ci 267353a5a1b3Sopenharmony_ci if (command == PA_COMMAND_LOOKUP_SINK) { 267453a5a1b3Sopenharmony_ci pa_sink *sink; 267553a5a1b3Sopenharmony_ci if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) 267653a5a1b3Sopenharmony_ci idx = sink->index; 267753a5a1b3Sopenharmony_ci } else { 267853a5a1b3Sopenharmony_ci pa_source *source; 267953a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_LOOKUP_SOURCE); 268053a5a1b3Sopenharmony_ci if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) 268153a5a1b3Sopenharmony_ci idx = source->index; 268253a5a1b3Sopenharmony_ci } 268353a5a1b3Sopenharmony_ci 268453a5a1b3Sopenharmony_ci if (idx == PA_IDXSET_INVALID) 268553a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 268653a5a1b3Sopenharmony_ci else { 268753a5a1b3Sopenharmony_ci pa_tagstruct *reply; 268853a5a1b3Sopenharmony_ci reply = reply_new(tag); 268953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, idx); 269053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 269153a5a1b3Sopenharmony_ci } 269253a5a1b3Sopenharmony_ci} 269353a5a1b3Sopenharmony_ci 269453a5a1b3Sopenharmony_cistatic void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 269553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 269653a5a1b3Sopenharmony_ci uint32_t idx; 269753a5a1b3Sopenharmony_ci playback_stream *s; 269853a5a1b3Sopenharmony_ci 269953a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 270053a5a1b3Sopenharmony_ci pa_assert(t); 270153a5a1b3Sopenharmony_ci 270253a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 270353a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 270453a5a1b3Sopenharmony_ci protocol_error(c); 270553a5a1b3Sopenharmony_ci return; 270653a5a1b3Sopenharmony_ci } 270753a5a1b3Sopenharmony_ci 270853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 270953a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 271053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 271153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 271253a5a1b3Sopenharmony_ci 271353a5a1b3Sopenharmony_ci pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL); 271453a5a1b3Sopenharmony_ci} 271553a5a1b3Sopenharmony_ci 271653a5a1b3Sopenharmony_cistatic void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 271753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 271853a5a1b3Sopenharmony_ci pa_tagstruct *reply; 271953a5a1b3Sopenharmony_ci const pa_mempool_stat *stat; 272053a5a1b3Sopenharmony_ci 272153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 272253a5a1b3Sopenharmony_ci pa_assert(t); 272353a5a1b3Sopenharmony_ci 272453a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 272553a5a1b3Sopenharmony_ci protocol_error(c); 272653a5a1b3Sopenharmony_ci return; 272753a5a1b3Sopenharmony_ci } 272853a5a1b3Sopenharmony_ci 272953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 273053a5a1b3Sopenharmony_ci 273153a5a1b3Sopenharmony_ci stat = pa_mempool_get_stat(c->protocol->core->mempool); 273253a5a1b3Sopenharmony_ci 273353a5a1b3Sopenharmony_ci reply = reply_new(tag); 273453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_allocated)); 273553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size)); 273653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated)); 273753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size)); 273853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core)); 273953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 274053a5a1b3Sopenharmony_ci} 274153a5a1b3Sopenharmony_ci 274253a5a1b3Sopenharmony_cistatic void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 274353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 274453a5a1b3Sopenharmony_ci pa_tagstruct *reply; 274553a5a1b3Sopenharmony_ci playback_stream *s; 274653a5a1b3Sopenharmony_ci struct timeval tv, now; 274753a5a1b3Sopenharmony_ci uint32_t idx; 274853a5a1b3Sopenharmony_ci 274953a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 275053a5a1b3Sopenharmony_ci pa_assert(t); 275153a5a1b3Sopenharmony_ci 275253a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 275353a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &tv) < 0 || 275453a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 275553a5a1b3Sopenharmony_ci protocol_error(c); 275653a5a1b3Sopenharmony_ci return; 275753a5a1b3Sopenharmony_ci } 275853a5a1b3Sopenharmony_ci 275953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 276053a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 276153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 276253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 276353a5a1b3Sopenharmony_ci 276453a5a1b3Sopenharmony_ci /* Get an atomic snapshot of all timing parameters */ 276553a5a1b3Sopenharmony_ci pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0); 276653a5a1b3Sopenharmony_ci 276753a5a1b3Sopenharmony_ci reply = reply_new(tag); 276853a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, 276953a5a1b3Sopenharmony_ci s->current_sink_latency + 277053a5a1b3Sopenharmony_ci pa_bytes_to_usec(s->render_memblockq_length, &s->sink_input->sink->sample_spec)); 277153a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, 0); 277253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, 277353a5a1b3Sopenharmony_ci s->playing_for > 0 && 277453a5a1b3Sopenharmony_ci s->sink_input->sink->state == PA_SINK_RUNNING && 277553a5a1b3Sopenharmony_ci s->sink_input->state == PA_SINK_INPUT_RUNNING); 277653a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(reply, &tv); 277753a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); 277853a5a1b3Sopenharmony_ci pa_tagstruct_puts64(reply, s->write_index); 277953a5a1b3Sopenharmony_ci pa_tagstruct_puts64(reply, s->read_index); 278053a5a1b3Sopenharmony_ci 278153a5a1b3Sopenharmony_ci if (c->version >= 13) { 278253a5a1b3Sopenharmony_ci pa_tagstruct_putu64(reply, s->underrun_for); 278353a5a1b3Sopenharmony_ci pa_tagstruct_putu64(reply, s->playing_for); 278453a5a1b3Sopenharmony_ci } 278553a5a1b3Sopenharmony_ci 278653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 278753a5a1b3Sopenharmony_ci} 278853a5a1b3Sopenharmony_ci 278953a5a1b3Sopenharmony_cistatic void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 279053a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 279153a5a1b3Sopenharmony_ci pa_tagstruct *reply; 279253a5a1b3Sopenharmony_ci record_stream *s; 279353a5a1b3Sopenharmony_ci struct timeval tv, now; 279453a5a1b3Sopenharmony_ci uint32_t idx; 279553a5a1b3Sopenharmony_ci 279653a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 279753a5a1b3Sopenharmony_ci pa_assert(t); 279853a5a1b3Sopenharmony_ci 279953a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 280053a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &tv) < 0 || 280153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 280253a5a1b3Sopenharmony_ci protocol_error(c); 280353a5a1b3Sopenharmony_ci return; 280453a5a1b3Sopenharmony_ci } 280553a5a1b3Sopenharmony_ci 280653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 280753a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 280853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 280953a5a1b3Sopenharmony_ci 281053a5a1b3Sopenharmony_ci /* Get an atomic snapshot of all timing parameters */ 281153a5a1b3Sopenharmony_ci pa_assert_se(pa_asyncmsgq_send(s->source_output->source->asyncmsgq, PA_MSGOBJECT(s->source_output), SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY, s, 0, NULL) == 0); 281253a5a1b3Sopenharmony_ci 281353a5a1b3Sopenharmony_ci reply = reply_new(tag); 281453a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, s->current_monitor_latency); 281553a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, 281653a5a1b3Sopenharmony_ci s->current_source_latency + 281753a5a1b3Sopenharmony_ci pa_bytes_to_usec(s->on_the_fly_snapshot, &s->source_output->sample_spec)); 281853a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, 281953a5a1b3Sopenharmony_ci s->source_output->source->state == PA_SOURCE_RUNNING && 282053a5a1b3Sopenharmony_ci s->source_output->state == PA_SOURCE_OUTPUT_RUNNING); 282153a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(reply, &tv); 282253a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now)); 282353a5a1b3Sopenharmony_ci pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq)); 282453a5a1b3Sopenharmony_ci pa_tagstruct_puts64(reply, pa_memblockq_get_read_index(s->memblockq)); 282553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 282653a5a1b3Sopenharmony_ci} 282753a5a1b3Sopenharmony_ci 282853a5a1b3Sopenharmony_cistatic void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 282953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 283053a5a1b3Sopenharmony_ci upload_stream *s; 283153a5a1b3Sopenharmony_ci uint32_t length; 283253a5a1b3Sopenharmony_ci const char *name = NULL; 283353a5a1b3Sopenharmony_ci pa_sample_spec ss; 283453a5a1b3Sopenharmony_ci pa_channel_map map; 283553a5a1b3Sopenharmony_ci pa_tagstruct *reply; 283653a5a1b3Sopenharmony_ci pa_proplist *p; 283753a5a1b3Sopenharmony_ci 283853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 283953a5a1b3Sopenharmony_ci pa_assert(t); 284053a5a1b3Sopenharmony_ci 284153a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &name) < 0 || 284253a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &ss) < 0 || 284353a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &map) < 0 || 284453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &length) < 0) { 284553a5a1b3Sopenharmony_ci protocol_error(c); 284653a5a1b3Sopenharmony_ci return; 284753a5a1b3Sopenharmony_ci } 284853a5a1b3Sopenharmony_ci 284953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 285053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); 285153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); 285253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID); 285353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (length % pa_frame_size(&ss)) == 0 && length > 0, tag, PA_ERR_INVALID); 285453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, length <= PA_SCACHE_ENTRY_SIZE_MAX, tag, PA_ERR_TOOLARGE); 285553a5a1b3Sopenharmony_ci 285653a5a1b3Sopenharmony_ci p = pa_proplist_new(); 285753a5a1b3Sopenharmony_ci 285853a5a1b3Sopenharmony_ci if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) || 285953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 286053a5a1b3Sopenharmony_ci 286153a5a1b3Sopenharmony_ci protocol_error(c); 286253a5a1b3Sopenharmony_ci pa_proplist_free(p); 286353a5a1b3Sopenharmony_ci return; 286453a5a1b3Sopenharmony_ci } 286553a5a1b3Sopenharmony_ci 286653a5a1b3Sopenharmony_ci if (c->version < 13) 286753a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_MEDIA_NAME, name); 286853a5a1b3Sopenharmony_ci else if (!name) 286953a5a1b3Sopenharmony_ci if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID))) 287053a5a1b3Sopenharmony_ci name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME); 287153a5a1b3Sopenharmony_ci 287253a5a1b3Sopenharmony_ci if (!name || !pa_namereg_is_valid_name(name)) { 287353a5a1b3Sopenharmony_ci pa_proplist_free(p); 287453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID); 287553a5a1b3Sopenharmony_ci } 287653a5a1b3Sopenharmony_ci 287753a5a1b3Sopenharmony_ci s = upload_stream_new(c, &ss, &map, name, length, p); 287853a5a1b3Sopenharmony_ci pa_proplist_free(p); 287953a5a1b3Sopenharmony_ci 288053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); 288153a5a1b3Sopenharmony_ci 288253a5a1b3Sopenharmony_ci reply = reply_new(tag); 288353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->index); 288453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, length); 288553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 288653a5a1b3Sopenharmony_ci} 288753a5a1b3Sopenharmony_ci 288853a5a1b3Sopenharmony_cistatic void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 288953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 289053a5a1b3Sopenharmony_ci uint32_t channel; 289153a5a1b3Sopenharmony_ci upload_stream *s; 289253a5a1b3Sopenharmony_ci uint32_t idx; 289353a5a1b3Sopenharmony_ci 289453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 289553a5a1b3Sopenharmony_ci pa_assert(t); 289653a5a1b3Sopenharmony_ci 289753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 289853a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 289953a5a1b3Sopenharmony_ci protocol_error(c); 290053a5a1b3Sopenharmony_ci return; 290153a5a1b3Sopenharmony_ci } 290253a5a1b3Sopenharmony_ci 290353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 290453a5a1b3Sopenharmony_ci 290553a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, channel); 290653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 290753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, upload_stream_isinstance(s), tag, PA_ERR_NOENTITY); 290853a5a1b3Sopenharmony_ci 290953a5a1b3Sopenharmony_ci if (!s->memchunk.memblock) 291053a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_TOOLARGE); 291153a5a1b3Sopenharmony_ci else if (pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, s->proplist, &idx) < 0) 291253a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INTERNAL); 291353a5a1b3Sopenharmony_ci else 291453a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 291553a5a1b3Sopenharmony_ci 291653a5a1b3Sopenharmony_ci upload_stream_unlink(s); 291753a5a1b3Sopenharmony_ci} 291853a5a1b3Sopenharmony_ci 291953a5a1b3Sopenharmony_cistatic void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 292053a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 292153a5a1b3Sopenharmony_ci uint32_t sink_index; 292253a5a1b3Sopenharmony_ci pa_volume_t volume; 292353a5a1b3Sopenharmony_ci pa_sink *sink; 292453a5a1b3Sopenharmony_ci const char *name, *sink_name; 292553a5a1b3Sopenharmony_ci uint32_t idx; 292653a5a1b3Sopenharmony_ci pa_proplist *p; 292753a5a1b3Sopenharmony_ci pa_tagstruct *reply; 292853a5a1b3Sopenharmony_ci 292953a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 293053a5a1b3Sopenharmony_ci pa_assert(t); 293153a5a1b3Sopenharmony_ci 293253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 293353a5a1b3Sopenharmony_ci 293453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &sink_index) < 0 || 293553a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &sink_name) < 0 || 293653a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &volume) < 0 || 293753a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0) { 293853a5a1b3Sopenharmony_ci protocol_error(c); 293953a5a1b3Sopenharmony_ci return; 294053a5a1b3Sopenharmony_ci } 294153a5a1b3Sopenharmony_ci 294253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name_or_wildcard(sink_name, PA_NAMEREG_SINK), tag, PA_ERR_INVALID); 294353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); 294453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); 294553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); 294653a5a1b3Sopenharmony_ci 294753a5a1b3Sopenharmony_ci if (sink_index != PA_INVALID_INDEX) 294853a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); 294953a5a1b3Sopenharmony_ci else 295053a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); 295153a5a1b3Sopenharmony_ci 295253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); 295353a5a1b3Sopenharmony_ci 295453a5a1b3Sopenharmony_ci p = pa_proplist_new(); 295553a5a1b3Sopenharmony_ci 295653a5a1b3Sopenharmony_ci if ((c->version >= 13 && pa_tagstruct_get_proplist(t, p) < 0) || 295753a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 295853a5a1b3Sopenharmony_ci protocol_error(c); 295953a5a1b3Sopenharmony_ci pa_proplist_free(p); 296053a5a1b3Sopenharmony_ci return; 296153a5a1b3Sopenharmony_ci } 296253a5a1b3Sopenharmony_ci 296353a5a1b3Sopenharmony_ci pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist); 296453a5a1b3Sopenharmony_ci 296553a5a1b3Sopenharmony_ci if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) { 296653a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 296753a5a1b3Sopenharmony_ci pa_proplist_free(p); 296853a5a1b3Sopenharmony_ci return; 296953a5a1b3Sopenharmony_ci } 297053a5a1b3Sopenharmony_ci 297153a5a1b3Sopenharmony_ci pa_proplist_free(p); 297253a5a1b3Sopenharmony_ci 297353a5a1b3Sopenharmony_ci reply = reply_new(tag); 297453a5a1b3Sopenharmony_ci 297553a5a1b3Sopenharmony_ci if (c->version >= 13) 297653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, idx); 297753a5a1b3Sopenharmony_ci 297853a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 297953a5a1b3Sopenharmony_ci} 298053a5a1b3Sopenharmony_ci 298153a5a1b3Sopenharmony_cistatic void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 298253a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 298353a5a1b3Sopenharmony_ci const char *name; 298453a5a1b3Sopenharmony_ci 298553a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 298653a5a1b3Sopenharmony_ci pa_assert(t); 298753a5a1b3Sopenharmony_ci 298853a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &name) < 0 || 298953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 299053a5a1b3Sopenharmony_ci protocol_error(c); 299153a5a1b3Sopenharmony_ci return; 299253a5a1b3Sopenharmony_ci } 299353a5a1b3Sopenharmony_ci 299453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 299553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); 299653a5a1b3Sopenharmony_ci 299753a5a1b3Sopenharmony_ci if (pa_scache_remove_item(c->protocol->core, name) < 0) { 299853a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 299953a5a1b3Sopenharmony_ci return; 300053a5a1b3Sopenharmony_ci } 300153a5a1b3Sopenharmony_ci 300253a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 300353a5a1b3Sopenharmony_ci} 300453a5a1b3Sopenharmony_ci 300553a5a1b3Sopenharmony_cistatic void fixup_sample_spec(pa_native_connection *c, pa_sample_spec *fixed, const pa_sample_spec *original) { 300653a5a1b3Sopenharmony_ci pa_assert(c); 300753a5a1b3Sopenharmony_ci pa_assert(fixed); 300853a5a1b3Sopenharmony_ci pa_assert(original); 300953a5a1b3Sopenharmony_ci 301053a5a1b3Sopenharmony_ci *fixed = *original; 301153a5a1b3Sopenharmony_ci 301253a5a1b3Sopenharmony_ci if (c->version < 12) { 301353a5a1b3Sopenharmony_ci /* Before protocol version 12 we didn't support S32 samples, 301453a5a1b3Sopenharmony_ci * so we need to lie about this to the client */ 301553a5a1b3Sopenharmony_ci 301653a5a1b3Sopenharmony_ci if (fixed->format == PA_SAMPLE_S32LE) 301753a5a1b3Sopenharmony_ci fixed->format = PA_SAMPLE_FLOAT32LE; 301853a5a1b3Sopenharmony_ci if (fixed->format == PA_SAMPLE_S32BE) 301953a5a1b3Sopenharmony_ci fixed->format = PA_SAMPLE_FLOAT32BE; 302053a5a1b3Sopenharmony_ci } 302153a5a1b3Sopenharmony_ci 302253a5a1b3Sopenharmony_ci if (c->version < 15) { 302353a5a1b3Sopenharmony_ci if (fixed->format == PA_SAMPLE_S24LE || fixed->format == PA_SAMPLE_S24_32LE) 302453a5a1b3Sopenharmony_ci fixed->format = PA_SAMPLE_FLOAT32LE; 302553a5a1b3Sopenharmony_ci if (fixed->format == PA_SAMPLE_S24BE || fixed->format == PA_SAMPLE_S24_32BE) 302653a5a1b3Sopenharmony_ci fixed->format = PA_SAMPLE_FLOAT32BE; 302753a5a1b3Sopenharmony_ci } 302853a5a1b3Sopenharmony_ci} 302953a5a1b3Sopenharmony_ci 303053a5a1b3Sopenharmony_cistatic void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink *sink) { 303153a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 303253a5a1b3Sopenharmony_ci 303353a5a1b3Sopenharmony_ci pa_assert(t); 303453a5a1b3Sopenharmony_ci pa_sink_assert_ref(sink); 303553a5a1b3Sopenharmony_ci 303653a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &sink->sample_spec); 303753a5a1b3Sopenharmony_ci 303853a5a1b3Sopenharmony_ci pa_tagstruct_put( 303953a5a1b3Sopenharmony_ci t, 304053a5a1b3Sopenharmony_ci PA_TAG_U32, sink->index, 304153a5a1b3Sopenharmony_ci PA_TAG_STRING, sink->name, 304253a5a1b3Sopenharmony_ci PA_TAG_STRING, pa_strnull(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)), 304353a5a1b3Sopenharmony_ci PA_TAG_SAMPLE_SPEC, &fixed_ss, 304453a5a1b3Sopenharmony_ci PA_TAG_CHANNEL_MAP, &sink->channel_map, 304553a5a1b3Sopenharmony_ci PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, 304653a5a1b3Sopenharmony_ci PA_TAG_CVOLUME, pa_sink_get_volume(sink, false), 304753a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, pa_sink_get_mute(sink, false), 304853a5a1b3Sopenharmony_ci PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, 304953a5a1b3Sopenharmony_ci PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, 305053a5a1b3Sopenharmony_ci PA_TAG_USEC, pa_sink_get_latency(sink), 305153a5a1b3Sopenharmony_ci PA_TAG_STRING, sink->driver, 305253a5a1b3Sopenharmony_ci PA_TAG_U32, sink->flags & PA_SINK_CLIENT_FLAGS_MASK, 305353a5a1b3Sopenharmony_ci PA_TAG_INVALID); 305453a5a1b3Sopenharmony_ci 305553a5a1b3Sopenharmony_ci if (c->version >= 13) { 305653a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, sink->proplist); 305753a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink)); 305853a5a1b3Sopenharmony_ci } 305953a5a1b3Sopenharmony_ci 306053a5a1b3Sopenharmony_ci if (c->version >= 15) { 306153a5a1b3Sopenharmony_ci pa_tagstruct_put_volume(t, sink->base_volume); 306253a5a1b3Sopenharmony_ci if (PA_UNLIKELY(sink->state == PA_SINK_INVALID_STATE)) 306353a5a1b3Sopenharmony_ci pa_log_error("Internal sink state is invalid."); 306453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, sink->state); 306553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, sink->n_volume_steps); 306653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX); 306753a5a1b3Sopenharmony_ci } 306853a5a1b3Sopenharmony_ci 306953a5a1b3Sopenharmony_ci if (c->version >= 16) { 307053a5a1b3Sopenharmony_ci void *state; 307153a5a1b3Sopenharmony_ci pa_device_port *p; 307253a5a1b3Sopenharmony_ci 307353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, pa_hashmap_size(sink->ports)); 307453a5a1b3Sopenharmony_ci 307553a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(p, sink->ports, state) { 307653a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->name); 307753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->description); 307853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->priority); 307953a5a1b3Sopenharmony_ci if (c->version >= 24) { 308053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->available); 308153a5a1b3Sopenharmony_ci if (c->version >= 34) { 308253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->availability_group); 308353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->type); 308453a5a1b3Sopenharmony_ci } 308553a5a1b3Sopenharmony_ci } 308653a5a1b3Sopenharmony_ci } 308753a5a1b3Sopenharmony_ci 308853a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL); 308953a5a1b3Sopenharmony_ci } 309053a5a1b3Sopenharmony_ci 309153a5a1b3Sopenharmony_ci if (c->version >= 21) { 309253a5a1b3Sopenharmony_ci uint32_t i; 309353a5a1b3Sopenharmony_ci pa_format_info *f; 309453a5a1b3Sopenharmony_ci pa_idxset *formats = pa_sink_get_formats(sink); 309553a5a1b3Sopenharmony_ci 309653a5a1b3Sopenharmony_ci pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats)); 309753a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(f, formats, i) { 309853a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(t, f); 309953a5a1b3Sopenharmony_ci } 310053a5a1b3Sopenharmony_ci 310153a5a1b3Sopenharmony_ci pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free); 310253a5a1b3Sopenharmony_ci } 310353a5a1b3Sopenharmony_ci} 310453a5a1b3Sopenharmony_ci 310553a5a1b3Sopenharmony_cistatic void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) { 310653a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 310753a5a1b3Sopenharmony_ci 310853a5a1b3Sopenharmony_ci pa_assert(t); 310953a5a1b3Sopenharmony_ci pa_source_assert_ref(source); 311053a5a1b3Sopenharmony_ci 311153a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &source->sample_spec); 311253a5a1b3Sopenharmony_ci 311353a5a1b3Sopenharmony_ci pa_tagstruct_put( 311453a5a1b3Sopenharmony_ci t, 311553a5a1b3Sopenharmony_ci PA_TAG_U32, source->index, 311653a5a1b3Sopenharmony_ci PA_TAG_STRING, source->name, 311753a5a1b3Sopenharmony_ci PA_TAG_STRING, pa_strnull(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)), 311853a5a1b3Sopenharmony_ci PA_TAG_SAMPLE_SPEC, &fixed_ss, 311953a5a1b3Sopenharmony_ci PA_TAG_CHANNEL_MAP, &source->channel_map, 312053a5a1b3Sopenharmony_ci PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX, 312153a5a1b3Sopenharmony_ci PA_TAG_CVOLUME, pa_source_get_volume(source, false), 312253a5a1b3Sopenharmony_ci PA_TAG_BOOLEAN, pa_source_get_mute(source, false), 312353a5a1b3Sopenharmony_ci PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, 312453a5a1b3Sopenharmony_ci PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, 312553a5a1b3Sopenharmony_ci PA_TAG_USEC, pa_source_get_latency(source), 312653a5a1b3Sopenharmony_ci PA_TAG_STRING, source->driver, 312753a5a1b3Sopenharmony_ci PA_TAG_U32, source->flags & PA_SOURCE_CLIENT_FLAGS_MASK, 312853a5a1b3Sopenharmony_ci PA_TAG_INVALID); 312953a5a1b3Sopenharmony_ci 313053a5a1b3Sopenharmony_ci if (c->version >= 13) { 313153a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, source->proplist); 313253a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source)); 313353a5a1b3Sopenharmony_ci } 313453a5a1b3Sopenharmony_ci 313553a5a1b3Sopenharmony_ci if (c->version >= 15) { 313653a5a1b3Sopenharmony_ci pa_tagstruct_put_volume(t, source->base_volume); 313753a5a1b3Sopenharmony_ci if (PA_UNLIKELY(source->state == PA_SOURCE_INVALID_STATE)) 313853a5a1b3Sopenharmony_ci pa_log_error("Internal source state is invalid."); 313953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, source->state); 314053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, source->n_volume_steps); 314153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX); 314253a5a1b3Sopenharmony_ci } 314353a5a1b3Sopenharmony_ci 314453a5a1b3Sopenharmony_ci if (c->version >= 16) { 314553a5a1b3Sopenharmony_ci void *state; 314653a5a1b3Sopenharmony_ci pa_device_port *p; 314753a5a1b3Sopenharmony_ci 314853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, pa_hashmap_size(source->ports)); 314953a5a1b3Sopenharmony_ci 315053a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(p, source->ports, state) { 315153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->name); 315253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->description); 315353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->priority); 315453a5a1b3Sopenharmony_ci if (c->version >= 24) { 315553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->available); 315653a5a1b3Sopenharmony_ci if (c->version >= 34) { 315753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->availability_group); 315853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->type); 315953a5a1b3Sopenharmony_ci } 316053a5a1b3Sopenharmony_ci } 316153a5a1b3Sopenharmony_ci } 316253a5a1b3Sopenharmony_ci 316353a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL); 316453a5a1b3Sopenharmony_ci } 316553a5a1b3Sopenharmony_ci 316653a5a1b3Sopenharmony_ci if (c->version >= 22) { 316753a5a1b3Sopenharmony_ci uint32_t i; 316853a5a1b3Sopenharmony_ci pa_format_info *f; 316953a5a1b3Sopenharmony_ci pa_idxset *formats = pa_source_get_formats(source); 317053a5a1b3Sopenharmony_ci 317153a5a1b3Sopenharmony_ci pa_tagstruct_putu8(t, (uint8_t) pa_idxset_size(formats)); 317253a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(f, formats, i) { 317353a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(t, f); 317453a5a1b3Sopenharmony_ci } 317553a5a1b3Sopenharmony_ci 317653a5a1b3Sopenharmony_ci pa_idxset_free(formats, (pa_free_cb_t) pa_format_info_free); 317753a5a1b3Sopenharmony_ci } 317853a5a1b3Sopenharmony_ci} 317953a5a1b3Sopenharmony_ci 318053a5a1b3Sopenharmony_cistatic void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) { 318153a5a1b3Sopenharmony_ci pa_assert(t); 318253a5a1b3Sopenharmony_ci pa_assert(client); 318353a5a1b3Sopenharmony_ci 318453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, client->index); 318553a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(client->proplist, PA_PROP_APPLICATION_NAME))); 318653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, client->module ? client->module->index : PA_INVALID_INDEX); 318753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, client->driver); 318853a5a1b3Sopenharmony_ci 318953a5a1b3Sopenharmony_ci if (c->version >= 13) 319053a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, client->proplist); 319153a5a1b3Sopenharmony_ci} 319253a5a1b3Sopenharmony_ci 319353a5a1b3Sopenharmony_cistatic void card_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_card *card) { 319453a5a1b3Sopenharmony_ci void *state = NULL; 319553a5a1b3Sopenharmony_ci pa_card_profile *p; 319653a5a1b3Sopenharmony_ci pa_device_port *port; 319753a5a1b3Sopenharmony_ci 319853a5a1b3Sopenharmony_ci pa_assert(t); 319953a5a1b3Sopenharmony_ci pa_assert(card); 320053a5a1b3Sopenharmony_ci 320153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, card->index); 320253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, card->name); 320353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, card->module ? card->module->index : PA_INVALID_INDEX); 320453a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, card->driver); 320553a5a1b3Sopenharmony_ci 320653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, pa_hashmap_size(card->profiles)); 320753a5a1b3Sopenharmony_ci 320853a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(p, card->profiles, state) { 320953a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->name); 321053a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->description); 321153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->n_sinks); 321253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->n_sources); 321353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, p->priority); 321453a5a1b3Sopenharmony_ci 321553a5a1b3Sopenharmony_ci if (c->version >= 29) 321653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (p->available != PA_AVAILABLE_NO)); 321753a5a1b3Sopenharmony_ci } 321853a5a1b3Sopenharmony_ci 321953a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, card->active_profile->name); 322053a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, card->proplist); 322153a5a1b3Sopenharmony_ci 322253a5a1b3Sopenharmony_ci if (c->version < 26) 322353a5a1b3Sopenharmony_ci return; 322453a5a1b3Sopenharmony_ci 322553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, pa_hashmap_size(card->ports)); 322653a5a1b3Sopenharmony_ci 322753a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(port, card->ports, state) { 322853a5a1b3Sopenharmony_ci void *state2; 322953a5a1b3Sopenharmony_ci 323053a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, port->name); 323153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, port->description); 323253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, port->priority); 323353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, port->available); 323453a5a1b3Sopenharmony_ci pa_tagstruct_putu8(t, port->direction); 323553a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, port->proplist); 323653a5a1b3Sopenharmony_ci 323753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, pa_hashmap_size(port->profiles)); 323853a5a1b3Sopenharmony_ci 323953a5a1b3Sopenharmony_ci PA_HASHMAP_FOREACH(p, port->profiles, state2) 324053a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, p->name); 324153a5a1b3Sopenharmony_ci 324253a5a1b3Sopenharmony_ci if (c->version >= 27) { 324353a5a1b3Sopenharmony_ci pa_tagstruct_puts64(t, port->latency_offset); 324453a5a1b3Sopenharmony_ci if (c->version >= 34) { 324553a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, port->availability_group); 324653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, port->type); 324753a5a1b3Sopenharmony_ci } 324853a5a1b3Sopenharmony_ci } 324953a5a1b3Sopenharmony_ci } 325053a5a1b3Sopenharmony_ci} 325153a5a1b3Sopenharmony_ci 325253a5a1b3Sopenharmony_cistatic void module_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_module *module) { 325353a5a1b3Sopenharmony_ci pa_assert(t); 325453a5a1b3Sopenharmony_ci pa_assert(module); 325553a5a1b3Sopenharmony_ci 325653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, module->index); 325753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, module->name); 325853a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, module->argument); 325953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) pa_module_get_n_used(module)); 326053a5a1b3Sopenharmony_ci 326153a5a1b3Sopenharmony_ci if (c->version < 15) 326253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, false); /* autoload is obsolete */ 326353a5a1b3Sopenharmony_ci 326453a5a1b3Sopenharmony_ci if (c->version >= 15) 326553a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, module->proplist); 326653a5a1b3Sopenharmony_ci} 326753a5a1b3Sopenharmony_ci 326853a5a1b3Sopenharmony_cistatic void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) { 326953a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 327053a5a1b3Sopenharmony_ci pa_usec_t sink_latency; 327153a5a1b3Sopenharmony_ci pa_cvolume v; 327253a5a1b3Sopenharmony_ci bool has_volume = false; 327353a5a1b3Sopenharmony_ci 327453a5a1b3Sopenharmony_ci pa_assert(t); 327553a5a1b3Sopenharmony_ci pa_sink_input_assert_ref(s); 327653a5a1b3Sopenharmony_ci 327753a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &s->sample_spec); 327853a5a1b3Sopenharmony_ci 327953a5a1b3Sopenharmony_ci has_volume = pa_sink_input_is_volume_readable(s); 328053a5a1b3Sopenharmony_ci if (has_volume) 328153a5a1b3Sopenharmony_ci pa_sink_input_get_volume(s, &v, true); 328253a5a1b3Sopenharmony_ci else 328353a5a1b3Sopenharmony_ci pa_cvolume_reset(&v, fixed_ss.channels); 328453a5a1b3Sopenharmony_ci 328553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 328653a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME))); 328753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); 328853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); 328953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->sink->index); 329053a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(t, &fixed_ss); 329153a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(t, &s->channel_map); 329253a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, &v); 329353a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency)); 329453a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, sink_latency); 329553a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); 329653a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, s->driver); 329753a5a1b3Sopenharmony_ci if (c->version >= 11) 329853a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->muted); 329953a5a1b3Sopenharmony_ci if (c->version >= 13) 330053a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, s->proplist); 330153a5a1b3Sopenharmony_ci if (c->version >= 19) 330253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->state == PA_SINK_INPUT_CORKED); 330353a5a1b3Sopenharmony_ci if (c->version >= 20) { 330453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, has_volume); 330553a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->volume_writable); 330653a5a1b3Sopenharmony_ci } 330753a5a1b3Sopenharmony_ci if (c->version >= 21) 330853a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(t, s->format); 330953a5a1b3Sopenharmony_ci} 331053a5a1b3Sopenharmony_ci 331153a5a1b3Sopenharmony_cistatic void source_output_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source_output *s) { 331253a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 331353a5a1b3Sopenharmony_ci pa_usec_t source_latency; 331453a5a1b3Sopenharmony_ci pa_cvolume v; 331553a5a1b3Sopenharmony_ci bool has_volume = false; 331653a5a1b3Sopenharmony_ci 331753a5a1b3Sopenharmony_ci pa_assert(t); 331853a5a1b3Sopenharmony_ci pa_source_output_assert_ref(s); 331953a5a1b3Sopenharmony_ci 332053a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &s->sample_spec); 332153a5a1b3Sopenharmony_ci 332253a5a1b3Sopenharmony_ci has_volume = pa_source_output_is_volume_readable(s); 332353a5a1b3Sopenharmony_ci if (has_volume) 332453a5a1b3Sopenharmony_ci pa_source_output_get_volume(s, &v, true); 332553a5a1b3Sopenharmony_ci else 332653a5a1b3Sopenharmony_ci pa_cvolume_reset(&v, fixed_ss.channels); 332753a5a1b3Sopenharmony_ci 332853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->index); 332953a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_strnull(pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME))); 333053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->module ? s->module->index : PA_INVALID_INDEX); 333153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->client ? s->client->index : PA_INVALID_INDEX); 333253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, s->source->index); 333353a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(t, &fixed_ss); 333453a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(t, &s->channel_map); 333553a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, pa_source_output_get_latency(s, &source_latency)); 333653a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, source_latency); 333753a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); 333853a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, s->driver); 333953a5a1b3Sopenharmony_ci if (c->version >= 13) 334053a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, s->proplist); 334153a5a1b3Sopenharmony_ci if (c->version >= 19) 334253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->state == PA_SOURCE_OUTPUT_CORKED); 334353a5a1b3Sopenharmony_ci if (c->version >= 22) { 334453a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, &v); 334553a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->muted); 334653a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, has_volume); 334753a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, s->volume_writable); 334853a5a1b3Sopenharmony_ci pa_tagstruct_put_format_info(t, s->format); 334953a5a1b3Sopenharmony_ci } 335053a5a1b3Sopenharmony_ci} 335153a5a1b3Sopenharmony_ci 335253a5a1b3Sopenharmony_cistatic void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_scache_entry *e) { 335353a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 335453a5a1b3Sopenharmony_ci pa_cvolume v; 335553a5a1b3Sopenharmony_ci 335653a5a1b3Sopenharmony_ci pa_assert(t); 335753a5a1b3Sopenharmony_ci pa_assert(e); 335853a5a1b3Sopenharmony_ci 335953a5a1b3Sopenharmony_ci if (e->memchunk.memblock) 336053a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &e->sample_spec); 336153a5a1b3Sopenharmony_ci else 336253a5a1b3Sopenharmony_ci memset(&fixed_ss, 0, sizeof(fixed_ss)); 336353a5a1b3Sopenharmony_ci 336453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, e->index); 336553a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, e->name); 336653a5a1b3Sopenharmony_ci 336753a5a1b3Sopenharmony_ci if (e->volume_is_set) 336853a5a1b3Sopenharmony_ci v = e->volume; 336953a5a1b3Sopenharmony_ci else 337053a5a1b3Sopenharmony_ci pa_cvolume_init(&v); 337153a5a1b3Sopenharmony_ci 337253a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, &v); 337353a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0); 337453a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(t, &fixed_ss); 337553a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(t, &e->channel_map); 337653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length); 337753a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, e->lazy); 337853a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, e->filename); 337953a5a1b3Sopenharmony_ci 338053a5a1b3Sopenharmony_ci if (c->version >= 13) 338153a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, e->proplist); 338253a5a1b3Sopenharmony_ci} 338353a5a1b3Sopenharmony_ci 338453a5a1b3Sopenharmony_cistatic void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 338553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 338653a5a1b3Sopenharmony_ci uint32_t idx; 338753a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 338853a5a1b3Sopenharmony_ci pa_source *source = NULL; 338953a5a1b3Sopenharmony_ci pa_client *client = NULL; 339053a5a1b3Sopenharmony_ci pa_card *card = NULL; 339153a5a1b3Sopenharmony_ci pa_module *module = NULL; 339253a5a1b3Sopenharmony_ci pa_sink_input *si = NULL; 339353a5a1b3Sopenharmony_ci pa_source_output *so = NULL; 339453a5a1b3Sopenharmony_ci pa_scache_entry *sce = NULL; 339553a5a1b3Sopenharmony_ci const char *name = NULL; 339653a5a1b3Sopenharmony_ci pa_tagstruct *reply; 339753a5a1b3Sopenharmony_ci 339853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 339953a5a1b3Sopenharmony_ci pa_assert(t); 340053a5a1b3Sopenharmony_ci 340153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 340253a5a1b3Sopenharmony_ci (command != PA_COMMAND_GET_CLIENT_INFO && 340353a5a1b3Sopenharmony_ci command != PA_COMMAND_GET_MODULE_INFO && 340453a5a1b3Sopenharmony_ci command != PA_COMMAND_GET_SINK_INPUT_INFO && 340553a5a1b3Sopenharmony_ci command != PA_COMMAND_GET_SOURCE_OUTPUT_INFO && 340653a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0) || 340753a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 340853a5a1b3Sopenharmony_ci protocol_error(c); 340953a5a1b3Sopenharmony_ci return; 341053a5a1b3Sopenharmony_ci } 341153a5a1b3Sopenharmony_ci 341253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 341353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || 341453a5a1b3Sopenharmony_ci (command == PA_COMMAND_GET_SINK_INFO && 341553a5a1b3Sopenharmony_ci pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SINK)) || 341653a5a1b3Sopenharmony_ci (command == PA_COMMAND_GET_SOURCE_INFO && 341753a5a1b3Sopenharmony_ci pa_namereg_is_valid_name_or_wildcard(name, PA_NAMEREG_SOURCE)) || 341853a5a1b3Sopenharmony_ci pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); 341953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, command == PA_COMMAND_GET_SINK_INFO || 342053a5a1b3Sopenharmony_ci command == PA_COMMAND_GET_SOURCE_INFO || 342153a5a1b3Sopenharmony_ci (idx != PA_INVALID_INDEX || name), tag, PA_ERR_INVALID); 342253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); 342353a5a1b3Sopenharmony_ci 342453a5a1b3Sopenharmony_ci if (command == PA_COMMAND_GET_SINK_INFO) { 342553a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 342653a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); 342753a5a1b3Sopenharmony_ci else 342853a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); 342953a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_GET_SOURCE_INFO) { 343053a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 343153a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx); 343253a5a1b3Sopenharmony_ci else 343353a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); 343453a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_GET_CARD_INFO) { 343553a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 343653a5a1b3Sopenharmony_ci card = pa_idxset_get_by_index(c->protocol->core->cards, idx); 343753a5a1b3Sopenharmony_ci else 343853a5a1b3Sopenharmony_ci card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD); 343953a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_GET_CLIENT_INFO) 344053a5a1b3Sopenharmony_ci client = pa_idxset_get_by_index(c->protocol->core->clients, idx); 344153a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_MODULE_INFO) 344253a5a1b3Sopenharmony_ci module = pa_idxset_get_by_index(c->protocol->core->modules, idx); 344353a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SINK_INPUT_INFO) 344453a5a1b3Sopenharmony_ci si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); 344553a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO) 344653a5a1b3Sopenharmony_ci so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); 344753a5a1b3Sopenharmony_ci else { 344853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO); 344953a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 345053a5a1b3Sopenharmony_ci sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); 345153a5a1b3Sopenharmony_ci else 345253a5a1b3Sopenharmony_ci sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE); 345353a5a1b3Sopenharmony_ci } 345453a5a1b3Sopenharmony_ci 345553a5a1b3Sopenharmony_ci if (!sink && !source && !client && !card && !module && !si && !so && !sce) { 345653a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); 345753a5a1b3Sopenharmony_ci return; 345853a5a1b3Sopenharmony_ci } 345953a5a1b3Sopenharmony_ci 346053a5a1b3Sopenharmony_ci reply = reply_new(tag); 346153a5a1b3Sopenharmony_ci if (sink) 346253a5a1b3Sopenharmony_ci sink_fill_tagstruct(c, reply, sink); 346353a5a1b3Sopenharmony_ci else if (source) 346453a5a1b3Sopenharmony_ci source_fill_tagstruct(c, reply, source); 346553a5a1b3Sopenharmony_ci else if (client) 346653a5a1b3Sopenharmony_ci client_fill_tagstruct(c, reply, client); 346753a5a1b3Sopenharmony_ci else if (card) 346853a5a1b3Sopenharmony_ci card_fill_tagstruct(c, reply, card); 346953a5a1b3Sopenharmony_ci else if (module) 347053a5a1b3Sopenharmony_ci module_fill_tagstruct(c, reply, module); 347153a5a1b3Sopenharmony_ci else if (si) 347253a5a1b3Sopenharmony_ci sink_input_fill_tagstruct(c, reply, si); 347353a5a1b3Sopenharmony_ci else if (so) 347453a5a1b3Sopenharmony_ci source_output_fill_tagstruct(c, reply, so); 347553a5a1b3Sopenharmony_ci else 347653a5a1b3Sopenharmony_ci scache_fill_tagstruct(c, reply, sce); 347753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 347853a5a1b3Sopenharmony_ci} 347953a5a1b3Sopenharmony_ci 348053a5a1b3Sopenharmony_cistatic void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 348153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 348253a5a1b3Sopenharmony_ci pa_idxset *i; 348353a5a1b3Sopenharmony_ci uint32_t idx; 348453a5a1b3Sopenharmony_ci void *p; 348553a5a1b3Sopenharmony_ci pa_tagstruct *reply; 348653a5a1b3Sopenharmony_ci 348753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 348853a5a1b3Sopenharmony_ci pa_assert(t); 348953a5a1b3Sopenharmony_ci 349053a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 349153a5a1b3Sopenharmony_ci protocol_error(c); 349253a5a1b3Sopenharmony_ci return; 349353a5a1b3Sopenharmony_ci } 349453a5a1b3Sopenharmony_ci 349553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 349653a5a1b3Sopenharmony_ci 349753a5a1b3Sopenharmony_ci reply = reply_new(tag); 349853a5a1b3Sopenharmony_ci 349953a5a1b3Sopenharmony_ci if (command == PA_COMMAND_GET_SINK_INFO_LIST) 350053a5a1b3Sopenharmony_ci i = c->protocol->core->sinks; 350153a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) 350253a5a1b3Sopenharmony_ci i = c->protocol->core->sources; 350353a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) 350453a5a1b3Sopenharmony_ci i = c->protocol->core->clients; 350553a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_CARD_INFO_LIST) 350653a5a1b3Sopenharmony_ci i = c->protocol->core->cards; 350753a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) 350853a5a1b3Sopenharmony_ci i = c->protocol->core->modules; 350953a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) 351053a5a1b3Sopenharmony_ci i = c->protocol->core->sink_inputs; 351153a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) 351253a5a1b3Sopenharmony_ci i = c->protocol->core->source_outputs; 351353a5a1b3Sopenharmony_ci else { 351453a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); 351553a5a1b3Sopenharmony_ci i = c->protocol->core->scache; 351653a5a1b3Sopenharmony_ci } 351753a5a1b3Sopenharmony_ci 351853a5a1b3Sopenharmony_ci if (i) { 351953a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(p, i, idx) { 352053a5a1b3Sopenharmony_ci if (command == PA_COMMAND_GET_SINK_INFO_LIST) 352153a5a1b3Sopenharmony_ci sink_fill_tagstruct(c, reply, p); 352253a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SOURCE_INFO_LIST) 352353a5a1b3Sopenharmony_ci source_fill_tagstruct(c, reply, p); 352453a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_CLIENT_INFO_LIST) 352553a5a1b3Sopenharmony_ci client_fill_tagstruct(c, reply, p); 352653a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_CARD_INFO_LIST) 352753a5a1b3Sopenharmony_ci card_fill_tagstruct(c, reply, p); 352853a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_MODULE_INFO_LIST) 352953a5a1b3Sopenharmony_ci module_fill_tagstruct(c, reply, p); 353053a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SINK_INPUT_INFO_LIST) 353153a5a1b3Sopenharmony_ci sink_input_fill_tagstruct(c, reply, p); 353253a5a1b3Sopenharmony_ci else if (command == PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST) 353353a5a1b3Sopenharmony_ci source_output_fill_tagstruct(c, reply, p); 353453a5a1b3Sopenharmony_ci else { 353553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_GET_SAMPLE_INFO_LIST); 353653a5a1b3Sopenharmony_ci scache_fill_tagstruct(c, reply, p); 353753a5a1b3Sopenharmony_ci } 353853a5a1b3Sopenharmony_ci } 353953a5a1b3Sopenharmony_ci } 354053a5a1b3Sopenharmony_ci 354153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 354253a5a1b3Sopenharmony_ci} 354353a5a1b3Sopenharmony_ci 354453a5a1b3Sopenharmony_cistatic void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 354553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 354653a5a1b3Sopenharmony_ci pa_tagstruct *reply; 354753a5a1b3Sopenharmony_ci pa_sample_spec fixed_ss; 354853a5a1b3Sopenharmony_ci char *h, *u; 354953a5a1b3Sopenharmony_ci pa_core *core; 355053a5a1b3Sopenharmony_ci 355153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 355253a5a1b3Sopenharmony_ci pa_assert(t); 355353a5a1b3Sopenharmony_ci 355453a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 355553a5a1b3Sopenharmony_ci protocol_error(c); 355653a5a1b3Sopenharmony_ci return; 355753a5a1b3Sopenharmony_ci } 355853a5a1b3Sopenharmony_ci 355953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 356053a5a1b3Sopenharmony_ci 356153a5a1b3Sopenharmony_ci reply = reply_new(tag); 356253a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, PACKAGE_NAME); 356353a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, PACKAGE_VERSION); 356453a5a1b3Sopenharmony_ci 356553a5a1b3Sopenharmony_ci u = pa_get_user_name_malloc(); 356653a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, u); 356753a5a1b3Sopenharmony_ci pa_xfree(u); 356853a5a1b3Sopenharmony_ci 356953a5a1b3Sopenharmony_ci h = pa_get_host_name_malloc(); 357053a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, h); 357153a5a1b3Sopenharmony_ci pa_xfree(h); 357253a5a1b3Sopenharmony_ci 357353a5a1b3Sopenharmony_ci core = c->protocol->core; 357453a5a1b3Sopenharmony_ci 357553a5a1b3Sopenharmony_ci fixup_sample_spec(c, &fixed_ss, &core->default_sample_spec); 357653a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(reply, &fixed_ss); 357753a5a1b3Sopenharmony_ci 357853a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, core->default_sink ? core->default_sink->name : NULL); 357953a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, core->default_source ? core->default_source->name : NULL); 358053a5a1b3Sopenharmony_ci 358153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, c->protocol->core->cookie); 358253a5a1b3Sopenharmony_ci 358353a5a1b3Sopenharmony_ci if (c->version >= 15) 358453a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(reply, &core->default_channel_map); 358553a5a1b3Sopenharmony_ci 358653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 358753a5a1b3Sopenharmony_ci} 358853a5a1b3Sopenharmony_ci 358953a5a1b3Sopenharmony_cistatic void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { 359053a5a1b3Sopenharmony_ci pa_tagstruct *t; 359153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 359253a5a1b3Sopenharmony_ci 359353a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 359453a5a1b3Sopenharmony_ci 359553a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 359653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE_EVENT); 359753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); 359853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, e); 359953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, idx); 360053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 360153a5a1b3Sopenharmony_ci} 360253a5a1b3Sopenharmony_ci 360353a5a1b3Sopenharmony_cistatic void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 360453a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 360553a5a1b3Sopenharmony_ci pa_subscription_mask_t m; 360653a5a1b3Sopenharmony_ci 360753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 360853a5a1b3Sopenharmony_ci pa_assert(t); 360953a5a1b3Sopenharmony_ci 361053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &m) < 0 || 361153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 361253a5a1b3Sopenharmony_ci protocol_error(c); 361353a5a1b3Sopenharmony_ci return; 361453a5a1b3Sopenharmony_ci } 361553a5a1b3Sopenharmony_ci 361653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 361753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (m & ~PA_SUBSCRIPTION_MASK_ALL) == 0, tag, PA_ERR_INVALID); 361853a5a1b3Sopenharmony_ci 361953a5a1b3Sopenharmony_ci if (c->subscription) 362053a5a1b3Sopenharmony_ci pa_subscription_free(c->subscription); 362153a5a1b3Sopenharmony_ci 362253a5a1b3Sopenharmony_ci if (m != 0) { 362353a5a1b3Sopenharmony_ci c->subscription = pa_subscription_new(c->protocol->core, m, subscription_cb, c); 362453a5a1b3Sopenharmony_ci pa_assert(c->subscription); 362553a5a1b3Sopenharmony_ci } else 362653a5a1b3Sopenharmony_ci c->subscription = NULL; 362753a5a1b3Sopenharmony_ci 362853a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 362953a5a1b3Sopenharmony_ci} 363053a5a1b3Sopenharmony_ci 363153a5a1b3Sopenharmony_cistatic void command_set_volume( 363253a5a1b3Sopenharmony_ci pa_pdispatch *pd, 363353a5a1b3Sopenharmony_ci uint32_t command, 363453a5a1b3Sopenharmony_ci uint32_t tag, 363553a5a1b3Sopenharmony_ci pa_tagstruct *t, 363653a5a1b3Sopenharmony_ci void *userdata) { 363753a5a1b3Sopenharmony_ci 363853a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 363953a5a1b3Sopenharmony_ci uint32_t idx; 364053a5a1b3Sopenharmony_ci pa_cvolume volume; 364153a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 364253a5a1b3Sopenharmony_ci pa_source *source = NULL; 364353a5a1b3Sopenharmony_ci pa_sink_input *si = NULL; 364453a5a1b3Sopenharmony_ci pa_source_output *so = NULL; 364553a5a1b3Sopenharmony_ci const char *name = NULL; 364653a5a1b3Sopenharmony_ci const char *client_name; 364753a5a1b3Sopenharmony_ci 364853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 364953a5a1b3Sopenharmony_ci pa_assert(t); 365053a5a1b3Sopenharmony_ci 365153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 365253a5a1b3Sopenharmony_ci (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || 365353a5a1b3Sopenharmony_ci (command == PA_COMMAND_SET_SOURCE_VOLUME && pa_tagstruct_gets(t, &name) < 0) || 365453a5a1b3Sopenharmony_ci pa_tagstruct_get_cvolume(t, &volume) || 365553a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 365653a5a1b3Sopenharmony_ci protocol_error(c); 365753a5a1b3Sopenharmony_ci return; 365853a5a1b3Sopenharmony_ci } 365953a5a1b3Sopenharmony_ci 366053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 366153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_VOLUME ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); 366253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 366353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); 366453a5a1b3Sopenharmony_ci 366553a5a1b3Sopenharmony_ci switch (command) { 366653a5a1b3Sopenharmony_ci 366753a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SINK_VOLUME: 366853a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 366953a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); 367053a5a1b3Sopenharmony_ci else 367153a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); 367253a5a1b3Sopenharmony_ci break; 367353a5a1b3Sopenharmony_ci 367453a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SOURCE_VOLUME: 367553a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 367653a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx); 367753a5a1b3Sopenharmony_ci else 367853a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); 367953a5a1b3Sopenharmony_ci break; 368053a5a1b3Sopenharmony_ci 368153a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SINK_INPUT_VOLUME: 368253a5a1b3Sopenharmony_ci si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); 368353a5a1b3Sopenharmony_ci break; 368453a5a1b3Sopenharmony_ci 368553a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME: 368653a5a1b3Sopenharmony_ci so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); 368753a5a1b3Sopenharmony_ci break; 368853a5a1b3Sopenharmony_ci 368953a5a1b3Sopenharmony_ci default: 369053a5a1b3Sopenharmony_ci pa_assert_not_reached(); 369153a5a1b3Sopenharmony_ci } 369253a5a1b3Sopenharmony_ci 369353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY); 369453a5a1b3Sopenharmony_ci 369553a5a1b3Sopenharmony_ci client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); 369653a5a1b3Sopenharmony_ci 369753a5a1b3Sopenharmony_ci if (sink) { 369853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &sink->sample_spec), tag, PA_ERR_INVALID); 369953a5a1b3Sopenharmony_ci 370053a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes volume of sink %s.", client_name, sink->name); 370153a5a1b3Sopenharmony_ci pa_sink_set_volume(sink, &volume, true, true); 370253a5a1b3Sopenharmony_ci } else if (source) { 370353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &source->sample_spec), tag, PA_ERR_INVALID); 370453a5a1b3Sopenharmony_ci 370553a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes volume of source %s.", client_name, source->name); 370653a5a1b3Sopenharmony_ci pa_source_set_volume(source, &volume, true, true); 370753a5a1b3Sopenharmony_ci } else if (si) { 370853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, si->volume_writable, tag, PA_ERR_BADSTATE); 370953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &si->sample_spec), tag, PA_ERR_INVALID); 371053a5a1b3Sopenharmony_ci 371153a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes volume of sink input %s.", 371253a5a1b3Sopenharmony_ci client_name, 371353a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); 371453a5a1b3Sopenharmony_ci pa_sink_input_set_volume(si, &volume, true, true); 371553a5a1b3Sopenharmony_ci } else if (so) { 371653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, so->volume_writable, tag, PA_ERR_BADSTATE); 371753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, volume.channels == 1 || pa_cvolume_compatible(&volume, &so->sample_spec), tag, PA_ERR_INVALID); 371853a5a1b3Sopenharmony_ci 371953a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes volume of source output %s.", 372053a5a1b3Sopenharmony_ci client_name, 372153a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME))); 372253a5a1b3Sopenharmony_ci pa_source_output_set_volume(so, &volume, true, true); 372353a5a1b3Sopenharmony_ci } 372453a5a1b3Sopenharmony_ci 372553a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 372653a5a1b3Sopenharmony_ci} 372753a5a1b3Sopenharmony_ci 372853a5a1b3Sopenharmony_cistatic void command_set_mute( 372953a5a1b3Sopenharmony_ci pa_pdispatch *pd, 373053a5a1b3Sopenharmony_ci uint32_t command, 373153a5a1b3Sopenharmony_ci uint32_t tag, 373253a5a1b3Sopenharmony_ci pa_tagstruct *t, 373353a5a1b3Sopenharmony_ci void *userdata) { 373453a5a1b3Sopenharmony_ci 373553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 373653a5a1b3Sopenharmony_ci uint32_t idx; 373753a5a1b3Sopenharmony_ci bool mute; 373853a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 373953a5a1b3Sopenharmony_ci pa_source *source = NULL; 374053a5a1b3Sopenharmony_ci pa_sink_input *si = NULL; 374153a5a1b3Sopenharmony_ci pa_source_output *so = NULL; 374253a5a1b3Sopenharmony_ci const char *name = NULL, *client_name; 374353a5a1b3Sopenharmony_ci 374453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 374553a5a1b3Sopenharmony_ci pa_assert(t); 374653a5a1b3Sopenharmony_ci 374753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 374853a5a1b3Sopenharmony_ci (command == PA_COMMAND_SET_SINK_MUTE && pa_tagstruct_gets(t, &name) < 0) || 374953a5a1b3Sopenharmony_ci (command == PA_COMMAND_SET_SOURCE_MUTE && pa_tagstruct_gets(t, &name) < 0) || 375053a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &mute) || 375153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 375253a5a1b3Sopenharmony_ci protocol_error(c); 375353a5a1b3Sopenharmony_ci return; 375453a5a1b3Sopenharmony_ci } 375553a5a1b3Sopenharmony_ci 375653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 375753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_MUTE ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); 375853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 375953a5a1b3Sopenharmony_ci 376053a5a1b3Sopenharmony_ci switch (command) { 376153a5a1b3Sopenharmony_ci 376253a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SINK_MUTE: 376353a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 376453a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); 376553a5a1b3Sopenharmony_ci else 376653a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); 376753a5a1b3Sopenharmony_ci 376853a5a1b3Sopenharmony_ci break; 376953a5a1b3Sopenharmony_ci 377053a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SOURCE_MUTE: 377153a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 377253a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx); 377353a5a1b3Sopenharmony_ci else 377453a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); 377553a5a1b3Sopenharmony_ci 377653a5a1b3Sopenharmony_ci break; 377753a5a1b3Sopenharmony_ci 377853a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SINK_INPUT_MUTE: 377953a5a1b3Sopenharmony_ci si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); 378053a5a1b3Sopenharmony_ci break; 378153a5a1b3Sopenharmony_ci 378253a5a1b3Sopenharmony_ci case PA_COMMAND_SET_SOURCE_OUTPUT_MUTE: 378353a5a1b3Sopenharmony_ci so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); 378453a5a1b3Sopenharmony_ci break; 378553a5a1b3Sopenharmony_ci 378653a5a1b3Sopenharmony_ci default: 378753a5a1b3Sopenharmony_ci pa_assert_not_reached(); 378853a5a1b3Sopenharmony_ci } 378953a5a1b3Sopenharmony_ci 379053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, si || so || sink || source, tag, PA_ERR_NOENTITY); 379153a5a1b3Sopenharmony_ci 379253a5a1b3Sopenharmony_ci client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); 379353a5a1b3Sopenharmony_ci 379453a5a1b3Sopenharmony_ci if (sink) { 379553a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes mute of sink %s.", client_name, sink->name); 379653a5a1b3Sopenharmony_ci pa_sink_set_mute(sink, mute, true); 379753a5a1b3Sopenharmony_ci } else if (source) { 379853a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes mute of source %s.", client_name, source->name); 379953a5a1b3Sopenharmony_ci pa_source_set_mute(source, mute, true); 380053a5a1b3Sopenharmony_ci } else if (si) { 380153a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes mute of sink input %s.", 380253a5a1b3Sopenharmony_ci client_name, 380353a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME))); 380453a5a1b3Sopenharmony_ci pa_sink_input_set_mute(si, mute, true); 380553a5a1b3Sopenharmony_ci } else if (so) { 380653a5a1b3Sopenharmony_ci pa_log_debug("Client %s changes mute of source output %s.", 380753a5a1b3Sopenharmony_ci client_name, 380853a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(so->proplist, PA_PROP_MEDIA_NAME))); 380953a5a1b3Sopenharmony_ci pa_source_output_set_mute(so, mute, true); 381053a5a1b3Sopenharmony_ci } 381153a5a1b3Sopenharmony_ci 381253a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 381353a5a1b3Sopenharmony_ci} 381453a5a1b3Sopenharmony_ci 381553a5a1b3Sopenharmony_cistatic void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 381653a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 381753a5a1b3Sopenharmony_ci uint32_t idx; 381853a5a1b3Sopenharmony_ci bool b; 381953a5a1b3Sopenharmony_ci playback_stream *s; 382053a5a1b3Sopenharmony_ci 382153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 382253a5a1b3Sopenharmony_ci pa_assert(t); 382353a5a1b3Sopenharmony_ci 382453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 382553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &b) < 0 || 382653a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 382753a5a1b3Sopenharmony_ci protocol_error(c); 382853a5a1b3Sopenharmony_ci return; 382953a5a1b3Sopenharmony_ci } 383053a5a1b3Sopenharmony_ci 383153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 383253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); 383353a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 383453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 383553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 383653a5a1b3Sopenharmony_ci 383753a5a1b3Sopenharmony_ci pa_sink_input_cork(s->sink_input, b); 383853a5a1b3Sopenharmony_ci 383953a5a1b3Sopenharmony_ci if (b) 384053a5a1b3Sopenharmony_ci s->is_underrun = true; 384153a5a1b3Sopenharmony_ci 384253a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 384353a5a1b3Sopenharmony_ci} 384453a5a1b3Sopenharmony_ci 384553a5a1b3Sopenharmony_cistatic void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 384653a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 384753a5a1b3Sopenharmony_ci uint32_t idx; 384853a5a1b3Sopenharmony_ci playback_stream *s; 384953a5a1b3Sopenharmony_ci 385053a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 385153a5a1b3Sopenharmony_ci pa_assert(t); 385253a5a1b3Sopenharmony_ci 385353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 385453a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 385553a5a1b3Sopenharmony_ci protocol_error(c); 385653a5a1b3Sopenharmony_ci return; 385753a5a1b3Sopenharmony_ci } 385853a5a1b3Sopenharmony_ci 385953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 386053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); 386153a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 386253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 386353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 386453a5a1b3Sopenharmony_ci 386553a5a1b3Sopenharmony_ci switch (command) { 386653a5a1b3Sopenharmony_ci case PA_COMMAND_FLUSH_PLAYBACK_STREAM: 386753a5a1b3Sopenharmony_ci pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_FLUSH, NULL, 0, NULL); 386853a5a1b3Sopenharmony_ci break; 386953a5a1b3Sopenharmony_ci 387053a5a1b3Sopenharmony_ci case PA_COMMAND_PREBUF_PLAYBACK_STREAM: 387153a5a1b3Sopenharmony_ci pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_PREBUF_FORCE, NULL, 0, NULL); 387253a5a1b3Sopenharmony_ci break; 387353a5a1b3Sopenharmony_ci 387453a5a1b3Sopenharmony_ci case PA_COMMAND_TRIGGER_PLAYBACK_STREAM: 387553a5a1b3Sopenharmony_ci pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_TRIGGER, NULL, 0, NULL); 387653a5a1b3Sopenharmony_ci break; 387753a5a1b3Sopenharmony_ci 387853a5a1b3Sopenharmony_ci default: 387953a5a1b3Sopenharmony_ci pa_assert_not_reached(); 388053a5a1b3Sopenharmony_ci } 388153a5a1b3Sopenharmony_ci 388253a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 388353a5a1b3Sopenharmony_ci} 388453a5a1b3Sopenharmony_ci 388553a5a1b3Sopenharmony_cistatic void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 388653a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 388753a5a1b3Sopenharmony_ci uint32_t idx; 388853a5a1b3Sopenharmony_ci record_stream *s; 388953a5a1b3Sopenharmony_ci bool b; 389053a5a1b3Sopenharmony_ci 389153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 389253a5a1b3Sopenharmony_ci pa_assert(t); 389353a5a1b3Sopenharmony_ci 389453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 389553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &b) < 0 || 389653a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 389753a5a1b3Sopenharmony_ci protocol_error(c); 389853a5a1b3Sopenharmony_ci return; 389953a5a1b3Sopenharmony_ci } 390053a5a1b3Sopenharmony_ci 390153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 390253a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 390353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 390453a5a1b3Sopenharmony_ci 390553a5a1b3Sopenharmony_ci pa_source_output_cork(s->source_output, b); 390653a5a1b3Sopenharmony_ci pa_memblockq_prebuf_force(s->memblockq); 390753a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 390853a5a1b3Sopenharmony_ci} 390953a5a1b3Sopenharmony_ci 391053a5a1b3Sopenharmony_cistatic void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 391153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 391253a5a1b3Sopenharmony_ci uint32_t idx; 391353a5a1b3Sopenharmony_ci record_stream *s; 391453a5a1b3Sopenharmony_ci 391553a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 391653a5a1b3Sopenharmony_ci pa_assert(t); 391753a5a1b3Sopenharmony_ci 391853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 391953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 392053a5a1b3Sopenharmony_ci protocol_error(c); 392153a5a1b3Sopenharmony_ci return; 392253a5a1b3Sopenharmony_ci } 392353a5a1b3Sopenharmony_ci 392453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 392553a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 392653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 392753a5a1b3Sopenharmony_ci 392853a5a1b3Sopenharmony_ci pa_memblockq_flush_read(s->memblockq); 392953a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 393053a5a1b3Sopenharmony_ci} 393153a5a1b3Sopenharmony_ci 393253a5a1b3Sopenharmony_cistatic void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 393353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 393453a5a1b3Sopenharmony_ci uint32_t idx; 393553a5a1b3Sopenharmony_ci pa_buffer_attr a; 393653a5a1b3Sopenharmony_ci pa_tagstruct *reply; 393753a5a1b3Sopenharmony_ci 393853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 393953a5a1b3Sopenharmony_ci pa_assert(t); 394053a5a1b3Sopenharmony_ci 394153a5a1b3Sopenharmony_ci memset(&a, 0, sizeof(a)); 394253a5a1b3Sopenharmony_ci 394353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0) { 394453a5a1b3Sopenharmony_ci protocol_error(c); 394553a5a1b3Sopenharmony_ci return; 394653a5a1b3Sopenharmony_ci } 394753a5a1b3Sopenharmony_ci 394853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 394953a5a1b3Sopenharmony_ci 395053a5a1b3Sopenharmony_ci if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) { 395153a5a1b3Sopenharmony_ci playback_stream *s; 395253a5a1b3Sopenharmony_ci bool adjust_latency = false, early_requests = false; 395353a5a1b3Sopenharmony_ci 395453a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 395553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 395653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 395753a5a1b3Sopenharmony_ci 395853a5a1b3Sopenharmony_ci if (pa_tagstruct_get( 395953a5a1b3Sopenharmony_ci t, 396053a5a1b3Sopenharmony_ci PA_TAG_U32, &a.maxlength, 396153a5a1b3Sopenharmony_ci PA_TAG_U32, &a.tlength, 396253a5a1b3Sopenharmony_ci PA_TAG_U32, &a.prebuf, 396353a5a1b3Sopenharmony_ci PA_TAG_U32, &a.minreq, 396453a5a1b3Sopenharmony_ci PA_TAG_INVALID) < 0 || 396553a5a1b3Sopenharmony_ci (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || 396653a5a1b3Sopenharmony_ci (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || 396753a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 396853a5a1b3Sopenharmony_ci protocol_error(c); 396953a5a1b3Sopenharmony_ci return; 397053a5a1b3Sopenharmony_ci } 397153a5a1b3Sopenharmony_ci 397253a5a1b3Sopenharmony_ci s->adjust_latency = adjust_latency; 397353a5a1b3Sopenharmony_ci s->early_requests = early_requests; 397453a5a1b3Sopenharmony_ci s->buffer_attr_req = a; 397553a5a1b3Sopenharmony_ci 397653a5a1b3Sopenharmony_ci fix_playback_buffer_attr(s); 397753a5a1b3Sopenharmony_ci pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR, NULL, 0, NULL) == 0); 397853a5a1b3Sopenharmony_ci 397953a5a1b3Sopenharmony_ci reply = reply_new(tag); 398053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.maxlength); 398153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.tlength); 398253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.prebuf); 398353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.minreq); 398453a5a1b3Sopenharmony_ci 398553a5a1b3Sopenharmony_ci if (c->version >= 13) 398653a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, s->configured_sink_latency); 398753a5a1b3Sopenharmony_ci 398853a5a1b3Sopenharmony_ci } else { 398953a5a1b3Sopenharmony_ci record_stream *s; 399053a5a1b3Sopenharmony_ci bool adjust_latency = false, early_requests = false; 399153a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR); 399253a5a1b3Sopenharmony_ci 399353a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 399453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 399553a5a1b3Sopenharmony_ci 399653a5a1b3Sopenharmony_ci if (pa_tagstruct_get( 399753a5a1b3Sopenharmony_ci t, 399853a5a1b3Sopenharmony_ci PA_TAG_U32, &a.maxlength, 399953a5a1b3Sopenharmony_ci PA_TAG_U32, &a.fragsize, 400053a5a1b3Sopenharmony_ci PA_TAG_INVALID) < 0 || 400153a5a1b3Sopenharmony_ci (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || 400253a5a1b3Sopenharmony_ci (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || 400353a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 400453a5a1b3Sopenharmony_ci protocol_error(c); 400553a5a1b3Sopenharmony_ci return; 400653a5a1b3Sopenharmony_ci } 400753a5a1b3Sopenharmony_ci 400853a5a1b3Sopenharmony_ci s->adjust_latency = adjust_latency; 400953a5a1b3Sopenharmony_ci s->early_requests = early_requests; 401053a5a1b3Sopenharmony_ci s->buffer_attr_req = a; 401153a5a1b3Sopenharmony_ci 401253a5a1b3Sopenharmony_ci fix_record_buffer_attr_pre(s); 401353a5a1b3Sopenharmony_ci pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength); 401453a5a1b3Sopenharmony_ci pa_memblockq_get_attr(s->memblockq, &s->buffer_attr); 401553a5a1b3Sopenharmony_ci fix_record_buffer_attr_post(s); 401653a5a1b3Sopenharmony_ci 401753a5a1b3Sopenharmony_ci reply = reply_new(tag); 401853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.maxlength); 401953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, s->buffer_attr.fragsize); 402053a5a1b3Sopenharmony_ci 402153a5a1b3Sopenharmony_ci if (c->version >= 13) 402253a5a1b3Sopenharmony_ci pa_tagstruct_put_usec(reply, s->configured_source_latency); 402353a5a1b3Sopenharmony_ci } 402453a5a1b3Sopenharmony_ci 402553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 402653a5a1b3Sopenharmony_ci} 402753a5a1b3Sopenharmony_ci 402853a5a1b3Sopenharmony_cistatic void command_update_stream_sample_rate(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 402953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 403053a5a1b3Sopenharmony_ci uint32_t idx; 403153a5a1b3Sopenharmony_ci uint32_t rate; 403253a5a1b3Sopenharmony_ci 403353a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 403453a5a1b3Sopenharmony_ci pa_assert(t); 403553a5a1b3Sopenharmony_ci 403653a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 403753a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &rate) < 0 || 403853a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 403953a5a1b3Sopenharmony_ci protocol_error(c); 404053a5a1b3Sopenharmony_ci return; 404153a5a1b3Sopenharmony_ci } 404253a5a1b3Sopenharmony_ci 404353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 404453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_sample_rate_valid(rate), tag, PA_ERR_INVALID); 404553a5a1b3Sopenharmony_ci 404653a5a1b3Sopenharmony_ci if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE) { 404753a5a1b3Sopenharmony_ci playback_stream *s; 404853a5a1b3Sopenharmony_ci 404953a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 405053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 405153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 405253a5a1b3Sopenharmony_ci 405353a5a1b3Sopenharmony_ci pa_sink_input_set_rate(s->sink_input, rate); 405453a5a1b3Sopenharmony_ci 405553a5a1b3Sopenharmony_ci } else { 405653a5a1b3Sopenharmony_ci record_stream *s; 405753a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE); 405853a5a1b3Sopenharmony_ci 405953a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 406053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 406153a5a1b3Sopenharmony_ci 406253a5a1b3Sopenharmony_ci pa_source_output_set_rate(s->source_output, rate); 406353a5a1b3Sopenharmony_ci } 406453a5a1b3Sopenharmony_ci 406553a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 406653a5a1b3Sopenharmony_ci} 406753a5a1b3Sopenharmony_ci 406853a5a1b3Sopenharmony_cistatic void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 406953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 407053a5a1b3Sopenharmony_ci uint32_t idx; 407153a5a1b3Sopenharmony_ci uint32_t mode; 407253a5a1b3Sopenharmony_ci pa_proplist *p; 407353a5a1b3Sopenharmony_ci 407453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 407553a5a1b3Sopenharmony_ci pa_assert(t); 407653a5a1b3Sopenharmony_ci 407753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 407853a5a1b3Sopenharmony_ci 407953a5a1b3Sopenharmony_ci p = pa_proplist_new(); 408053a5a1b3Sopenharmony_ci 408153a5a1b3Sopenharmony_ci if (command == PA_COMMAND_UPDATE_CLIENT_PROPLIST) { 408253a5a1b3Sopenharmony_ci 408353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &mode) < 0 || 408453a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, p) < 0 || 408553a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 408653a5a1b3Sopenharmony_ci protocol_error(c); 408753a5a1b3Sopenharmony_ci pa_proplist_free(p); 408853a5a1b3Sopenharmony_ci return; 408953a5a1b3Sopenharmony_ci } 409053a5a1b3Sopenharmony_ci 409153a5a1b3Sopenharmony_ci } else { 409253a5a1b3Sopenharmony_ci 409353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 409453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &mode) < 0 || 409553a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, p) < 0 || 409653a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 409753a5a1b3Sopenharmony_ci protocol_error(c); 409853a5a1b3Sopenharmony_ci pa_proplist_free(p); 409953a5a1b3Sopenharmony_ci return; 410053a5a1b3Sopenharmony_ci } 410153a5a1b3Sopenharmony_ci } 410253a5a1b3Sopenharmony_ci 410353a5a1b3Sopenharmony_ci if (!(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE)) { 410453a5a1b3Sopenharmony_ci pa_proplist_free(p); 410553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_INVALID); 410653a5a1b3Sopenharmony_ci } 410753a5a1b3Sopenharmony_ci 410853a5a1b3Sopenharmony_ci if (command == PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST) { 410953a5a1b3Sopenharmony_ci playback_stream *s; 411053a5a1b3Sopenharmony_ci 411153a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 411253a5a1b3Sopenharmony_ci if (!s || !playback_stream_isinstance(s)) { 411353a5a1b3Sopenharmony_ci pa_proplist_free(p); 411453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY); 411553a5a1b3Sopenharmony_ci } 411653a5a1b3Sopenharmony_ci pa_sink_input_update_proplist(s->sink_input, mode, p); 411753a5a1b3Sopenharmony_ci 411853a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST) { 411953a5a1b3Sopenharmony_ci record_stream *s; 412053a5a1b3Sopenharmony_ci 412153a5a1b3Sopenharmony_ci if (!(s = pa_idxset_get_by_index(c->record_streams, idx))) { 412253a5a1b3Sopenharmony_ci pa_proplist_free(p); 412353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, false, tag, PA_ERR_NOENTITY); 412453a5a1b3Sopenharmony_ci } 412553a5a1b3Sopenharmony_ci pa_source_output_update_proplist(s->source_output, mode, p); 412653a5a1b3Sopenharmony_ci 412753a5a1b3Sopenharmony_ci } else { 412853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_UPDATE_CLIENT_PROPLIST); 412953a5a1b3Sopenharmony_ci 413053a5a1b3Sopenharmony_ci pa_client_update_proplist(c->client, mode, p); 413153a5a1b3Sopenharmony_ci } 413253a5a1b3Sopenharmony_ci 413353a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 413453a5a1b3Sopenharmony_ci pa_proplist_free(p); 413553a5a1b3Sopenharmony_ci} 413653a5a1b3Sopenharmony_ci 413753a5a1b3Sopenharmony_cistatic void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 413853a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 413953a5a1b3Sopenharmony_ci uint32_t idx; 414053a5a1b3Sopenharmony_ci unsigned changed = 0; 414153a5a1b3Sopenharmony_ci pa_proplist *p; 414253a5a1b3Sopenharmony_ci pa_strlist *l = NULL; 414353a5a1b3Sopenharmony_ci 414453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 414553a5a1b3Sopenharmony_ci pa_assert(t); 414653a5a1b3Sopenharmony_ci 414753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 414853a5a1b3Sopenharmony_ci 414953a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REMOVE_CLIENT_PROPLIST) { 415053a5a1b3Sopenharmony_ci 415153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0) { 415253a5a1b3Sopenharmony_ci protocol_error(c); 415353a5a1b3Sopenharmony_ci return; 415453a5a1b3Sopenharmony_ci } 415553a5a1b3Sopenharmony_ci } 415653a5a1b3Sopenharmony_ci 415753a5a1b3Sopenharmony_ci if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) { 415853a5a1b3Sopenharmony_ci playback_stream *s; 415953a5a1b3Sopenharmony_ci 416053a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 416153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 416253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 416353a5a1b3Sopenharmony_ci 416453a5a1b3Sopenharmony_ci p = s->sink_input->proplist; 416553a5a1b3Sopenharmony_ci 416653a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) { 416753a5a1b3Sopenharmony_ci record_stream *s; 416853a5a1b3Sopenharmony_ci 416953a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 417053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 417153a5a1b3Sopenharmony_ci 417253a5a1b3Sopenharmony_ci p = s->source_output->proplist; 417353a5a1b3Sopenharmony_ci } else { 417453a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST); 417553a5a1b3Sopenharmony_ci 417653a5a1b3Sopenharmony_ci p = c->client->proplist; 417753a5a1b3Sopenharmony_ci } 417853a5a1b3Sopenharmony_ci 417953a5a1b3Sopenharmony_ci for (;;) { 418053a5a1b3Sopenharmony_ci const char *k; 418153a5a1b3Sopenharmony_ci 418253a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &k) < 0) { 418353a5a1b3Sopenharmony_ci protocol_error(c); 418453a5a1b3Sopenharmony_ci pa_strlist_free(l); 418553a5a1b3Sopenharmony_ci return; 418653a5a1b3Sopenharmony_ci } 418753a5a1b3Sopenharmony_ci 418853a5a1b3Sopenharmony_ci if (!k) 418953a5a1b3Sopenharmony_ci break; 419053a5a1b3Sopenharmony_ci 419153a5a1b3Sopenharmony_ci l = pa_strlist_prepend(l, k); 419253a5a1b3Sopenharmony_ci } 419353a5a1b3Sopenharmony_ci 419453a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 419553a5a1b3Sopenharmony_ci protocol_error(c); 419653a5a1b3Sopenharmony_ci pa_strlist_free(l); 419753a5a1b3Sopenharmony_ci return; 419853a5a1b3Sopenharmony_ci } 419953a5a1b3Sopenharmony_ci 420053a5a1b3Sopenharmony_ci for (;;) { 420153a5a1b3Sopenharmony_ci char *z; 420253a5a1b3Sopenharmony_ci 420353a5a1b3Sopenharmony_ci l = pa_strlist_pop(l, &z); 420453a5a1b3Sopenharmony_ci 420553a5a1b3Sopenharmony_ci if (!z) 420653a5a1b3Sopenharmony_ci break; 420753a5a1b3Sopenharmony_ci 420853a5a1b3Sopenharmony_ci changed += (unsigned) (pa_proplist_unset(p, z) >= 0); 420953a5a1b3Sopenharmony_ci pa_xfree(z); 421053a5a1b3Sopenharmony_ci } 421153a5a1b3Sopenharmony_ci 421253a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 421353a5a1b3Sopenharmony_ci 421453a5a1b3Sopenharmony_ci if (changed) { 421553a5a1b3Sopenharmony_ci if (command == PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST) { 421653a5a1b3Sopenharmony_ci playback_stream *s; 421753a5a1b3Sopenharmony_ci 421853a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 421953a5a1b3Sopenharmony_ci pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->sink_input->index); 422053a5a1b3Sopenharmony_ci 422153a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST) { 422253a5a1b3Sopenharmony_ci record_stream *s; 422353a5a1b3Sopenharmony_ci 422453a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 422553a5a1b3Sopenharmony_ci pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT|PA_SUBSCRIPTION_EVENT_CHANGE, s->source_output->index); 422653a5a1b3Sopenharmony_ci 422753a5a1b3Sopenharmony_ci } else { 422853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_REMOVE_CLIENT_PROPLIST); 422953a5a1b3Sopenharmony_ci pa_subscription_post(c->protocol->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index); 423053a5a1b3Sopenharmony_ci } 423153a5a1b3Sopenharmony_ci } 423253a5a1b3Sopenharmony_ci} 423353a5a1b3Sopenharmony_ci 423453a5a1b3Sopenharmony_cistatic void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 423553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 423653a5a1b3Sopenharmony_ci const char *s; 423753a5a1b3Sopenharmony_ci 423853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 423953a5a1b3Sopenharmony_ci pa_assert(t); 424053a5a1b3Sopenharmony_ci 424153a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &s) < 0 || 424253a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 424353a5a1b3Sopenharmony_ci protocol_error(c); 424453a5a1b3Sopenharmony_ci return; 424553a5a1b3Sopenharmony_ci } 424653a5a1b3Sopenharmony_ci 424753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 424853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID); 424953a5a1b3Sopenharmony_ci 425053a5a1b3Sopenharmony_ci if (command == PA_COMMAND_SET_DEFAULT_SOURCE) { 425153a5a1b3Sopenharmony_ci pa_source *source; 425253a5a1b3Sopenharmony_ci 425353a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SOURCE); 425453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); 425553a5a1b3Sopenharmony_ci 425653a5a1b3Sopenharmony_ci pa_core_set_configured_default_source(c->protocol->core, source->name); 425753a5a1b3Sopenharmony_ci } else { 425853a5a1b3Sopenharmony_ci pa_sink *sink; 425953a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SET_DEFAULT_SINK); 426053a5a1b3Sopenharmony_ci 426153a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, s, PA_NAMEREG_SINK); 426253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); 426353a5a1b3Sopenharmony_ci 426453a5a1b3Sopenharmony_ci pa_core_set_configured_default_sink(c->protocol->core, sink->name); 426553a5a1b3Sopenharmony_ci } 426653a5a1b3Sopenharmony_ci 426753a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 426853a5a1b3Sopenharmony_ci} 426953a5a1b3Sopenharmony_ci 427053a5a1b3Sopenharmony_cistatic void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 427153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 427253a5a1b3Sopenharmony_ci uint32_t idx; 427353a5a1b3Sopenharmony_ci const char *name; 427453a5a1b3Sopenharmony_ci 427553a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 427653a5a1b3Sopenharmony_ci pa_assert(t); 427753a5a1b3Sopenharmony_ci 427853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 427953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 428053a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 428153a5a1b3Sopenharmony_ci protocol_error(c); 428253a5a1b3Sopenharmony_ci return; 428353a5a1b3Sopenharmony_ci } 428453a5a1b3Sopenharmony_ci 428553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 428653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, name && pa_utf8_valid(name), tag, PA_ERR_INVALID); 428753a5a1b3Sopenharmony_ci 428853a5a1b3Sopenharmony_ci if (command == PA_COMMAND_SET_PLAYBACK_STREAM_NAME) { 428953a5a1b3Sopenharmony_ci playback_stream *s; 429053a5a1b3Sopenharmony_ci 429153a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->output_streams, idx); 429253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 429353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); 429453a5a1b3Sopenharmony_ci 429553a5a1b3Sopenharmony_ci pa_sink_input_set_property(s->sink_input, PA_PROP_MEDIA_NAME, name); 429653a5a1b3Sopenharmony_ci 429753a5a1b3Sopenharmony_ci } else { 429853a5a1b3Sopenharmony_ci record_stream *s; 429953a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_NAME); 430053a5a1b3Sopenharmony_ci 430153a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->record_streams, idx); 430253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 430353a5a1b3Sopenharmony_ci 430453a5a1b3Sopenharmony_ci pa_source_output_set_property(s->source_output, PA_PROP_MEDIA_NAME, name); 430553a5a1b3Sopenharmony_ci } 430653a5a1b3Sopenharmony_ci 430753a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 430853a5a1b3Sopenharmony_ci} 430953a5a1b3Sopenharmony_ci 431053a5a1b3Sopenharmony_cistatic void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 431153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 431253a5a1b3Sopenharmony_ci uint32_t idx; 431353a5a1b3Sopenharmony_ci 431453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 431553a5a1b3Sopenharmony_ci pa_assert(t); 431653a5a1b3Sopenharmony_ci 431753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 431853a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 431953a5a1b3Sopenharmony_ci protocol_error(c); 432053a5a1b3Sopenharmony_ci return; 432153a5a1b3Sopenharmony_ci } 432253a5a1b3Sopenharmony_ci 432353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 432453a5a1b3Sopenharmony_ci 432553a5a1b3Sopenharmony_ci if (command == PA_COMMAND_KILL_CLIENT) { 432653a5a1b3Sopenharmony_ci pa_client *client; 432753a5a1b3Sopenharmony_ci 432853a5a1b3Sopenharmony_ci client = pa_idxset_get_by_index(c->protocol->core->clients, idx); 432953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, client, tag, PA_ERR_NOENTITY); 433053a5a1b3Sopenharmony_ci 433153a5a1b3Sopenharmony_ci pa_native_connection_ref(c); 433253a5a1b3Sopenharmony_ci pa_client_kill(client); 433353a5a1b3Sopenharmony_ci 433453a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_KILL_SINK_INPUT) { 433553a5a1b3Sopenharmony_ci pa_sink_input *s; 433653a5a1b3Sopenharmony_ci 433753a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); 433853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 433953a5a1b3Sopenharmony_ci 434053a5a1b3Sopenharmony_ci pa_native_connection_ref(c); 434153a5a1b3Sopenharmony_ci pa_sink_input_kill(s); 434253a5a1b3Sopenharmony_ci } else { 434353a5a1b3Sopenharmony_ci pa_source_output *s; 434453a5a1b3Sopenharmony_ci 434553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_KILL_SOURCE_OUTPUT); 434653a5a1b3Sopenharmony_ci 434753a5a1b3Sopenharmony_ci s = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); 434853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); 434953a5a1b3Sopenharmony_ci 435053a5a1b3Sopenharmony_ci pa_native_connection_ref(c); 435153a5a1b3Sopenharmony_ci pa_source_output_kill(s); 435253a5a1b3Sopenharmony_ci } 435353a5a1b3Sopenharmony_ci 435453a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 435553a5a1b3Sopenharmony_ci pa_native_connection_unref(c); 435653a5a1b3Sopenharmony_ci} 435753a5a1b3Sopenharmony_ci 435853a5a1b3Sopenharmony_cistatic void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 435953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 436053a5a1b3Sopenharmony_ci pa_module *m; 436153a5a1b3Sopenharmony_ci const char *name, *argument; 436253a5a1b3Sopenharmony_ci pa_tagstruct *reply; 436353a5a1b3Sopenharmony_ci 436453a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 436553a5a1b3Sopenharmony_ci pa_assert(t); 436653a5a1b3Sopenharmony_ci 436753a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &name) < 0 || 436853a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &argument) < 0 || 436953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 437053a5a1b3Sopenharmony_ci protocol_error(c); 437153a5a1b3Sopenharmony_ci return; 437253a5a1b3Sopenharmony_ci } 437353a5a1b3Sopenharmony_ci 437453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 437553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name) && !strchr(name, '/'), tag, PA_ERR_INVALID); 437653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); 437753a5a1b3Sopenharmony_ci 437853a5a1b3Sopenharmony_ci if (pa_module_load(&m, c->protocol->core, name, argument) < 0) { 437953a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_MODINITFAILED); 438053a5a1b3Sopenharmony_ci return; 438153a5a1b3Sopenharmony_ci } 438253a5a1b3Sopenharmony_ci 438353a5a1b3Sopenharmony_ci reply = reply_new(tag); 438453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, m->index); 438553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 438653a5a1b3Sopenharmony_ci} 438753a5a1b3Sopenharmony_ci 438853a5a1b3Sopenharmony_cistatic void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 438953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 439053a5a1b3Sopenharmony_ci uint32_t idx; 439153a5a1b3Sopenharmony_ci pa_module *m; 439253a5a1b3Sopenharmony_ci 439353a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 439453a5a1b3Sopenharmony_ci pa_assert(t); 439553a5a1b3Sopenharmony_ci 439653a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 439753a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 439853a5a1b3Sopenharmony_ci protocol_error(c); 439953a5a1b3Sopenharmony_ci return; 440053a5a1b3Sopenharmony_ci } 440153a5a1b3Sopenharmony_ci 440253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 440353a5a1b3Sopenharmony_ci m = pa_idxset_get_by_index(c->protocol->core->modules, idx); 440453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); 440553a5a1b3Sopenharmony_ci 440653a5a1b3Sopenharmony_ci pa_module_unload_request(m, false); 440753a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 440853a5a1b3Sopenharmony_ci} 440953a5a1b3Sopenharmony_ci 441053a5a1b3Sopenharmony_cistatic void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 441153a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 441253a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; 441353a5a1b3Sopenharmony_ci const char *name_device = NULL; 441453a5a1b3Sopenharmony_ci 441553a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 441653a5a1b3Sopenharmony_ci pa_assert(t); 441753a5a1b3Sopenharmony_ci 441853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 441953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &idx_device) < 0 || 442053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name_device) < 0 || 442153a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 442253a5a1b3Sopenharmony_ci protocol_error(c); 442353a5a1b3Sopenharmony_ci return; 442453a5a1b3Sopenharmony_ci } 442553a5a1b3Sopenharmony_ci 442653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 442753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); 442853a5a1b3Sopenharmony_ci 442953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name_or_wildcard(name_device, command == PA_COMMAND_MOVE_SINK_INPUT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); 443053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx_device != PA_INVALID_INDEX) ^ (name_device != NULL), tag, PA_ERR_INVALID); 443153a5a1b3Sopenharmony_ci 443253a5a1b3Sopenharmony_ci if (command == PA_COMMAND_MOVE_SINK_INPUT) { 443353a5a1b3Sopenharmony_ci pa_sink_input *si = NULL; 443453a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 443553a5a1b3Sopenharmony_ci 443653a5a1b3Sopenharmony_ci si = pa_idxset_get_by_index(c->protocol->core->sink_inputs, idx); 443753a5a1b3Sopenharmony_ci 443853a5a1b3Sopenharmony_ci if (idx_device != PA_INVALID_INDEX) 443953a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); 444053a5a1b3Sopenharmony_ci else 444153a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK); 444253a5a1b3Sopenharmony_ci 444353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); 444453a5a1b3Sopenharmony_ci 444553a5a1b3Sopenharmony_ci if (pa_sink_input_move_to(si, sink, true) < 0) { 444653a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 444753a5a1b3Sopenharmony_ci return; 444853a5a1b3Sopenharmony_ci } 444953a5a1b3Sopenharmony_ci } else { 445053a5a1b3Sopenharmony_ci pa_source_output *so = NULL; 445153a5a1b3Sopenharmony_ci pa_source *source; 445253a5a1b3Sopenharmony_ci 445353a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_MOVE_SOURCE_OUTPUT); 445453a5a1b3Sopenharmony_ci 445553a5a1b3Sopenharmony_ci so = pa_idxset_get_by_index(c->protocol->core->source_outputs, idx); 445653a5a1b3Sopenharmony_ci 445753a5a1b3Sopenharmony_ci if (idx_device != PA_INVALID_INDEX) 445853a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device); 445953a5a1b3Sopenharmony_ci else 446053a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE); 446153a5a1b3Sopenharmony_ci 446253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY); 446353a5a1b3Sopenharmony_ci 446453a5a1b3Sopenharmony_ci if (pa_source_output_move_to(so, source, true) < 0) { 446553a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 446653a5a1b3Sopenharmony_ci return; 446753a5a1b3Sopenharmony_ci } 446853a5a1b3Sopenharmony_ci } 446953a5a1b3Sopenharmony_ci 447053a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 447153a5a1b3Sopenharmony_ci} 447253a5a1b3Sopenharmony_ci 447353a5a1b3Sopenharmony_cistatic void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 447453a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 447553a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX; 447653a5a1b3Sopenharmony_ci const char *name = NULL; 447753a5a1b3Sopenharmony_ci bool b; 447853a5a1b3Sopenharmony_ci 447953a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 448053a5a1b3Sopenharmony_ci pa_assert(t); 448153a5a1b3Sopenharmony_ci 448253a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 448353a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 448453a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &b) < 0 || 448553a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 448653a5a1b3Sopenharmony_ci protocol_error(c); 448753a5a1b3Sopenharmony_ci return; 448853a5a1b3Sopenharmony_ci } 448953a5a1b3Sopenharmony_ci 449053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 449153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SUSPEND_SINK ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) || *name == 0, tag, PA_ERR_INVALID); 449253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 449353a5a1b3Sopenharmony_ci 449453a5a1b3Sopenharmony_ci if (command == PA_COMMAND_SUSPEND_SINK) { 449553a5a1b3Sopenharmony_ci 449653a5a1b3Sopenharmony_ci if (idx == PA_INVALID_INDEX && name && !*name) { 449753a5a1b3Sopenharmony_ci 449853a5a1b3Sopenharmony_ci pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming"); 449953a5a1b3Sopenharmony_ci 450053a5a1b3Sopenharmony_ci if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) { 450153a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 450253a5a1b3Sopenharmony_ci return; 450353a5a1b3Sopenharmony_ci } 450453a5a1b3Sopenharmony_ci } else { 450553a5a1b3Sopenharmony_ci pa_sink *sink = NULL; 450653a5a1b3Sopenharmony_ci 450753a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 450853a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); 450953a5a1b3Sopenharmony_ci else 451053a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); 451153a5a1b3Sopenharmony_ci 451253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); 451353a5a1b3Sopenharmony_ci 451453a5a1b3Sopenharmony_ci pa_log_debug("%s of sink %s requested by client %" PRIu32 ".", 451553a5a1b3Sopenharmony_ci b ? "Suspending" : "Resuming", sink->name, c->client->index); 451653a5a1b3Sopenharmony_ci 451753a5a1b3Sopenharmony_ci if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) { 451853a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 451953a5a1b3Sopenharmony_ci return; 452053a5a1b3Sopenharmony_ci } 452153a5a1b3Sopenharmony_ci } 452253a5a1b3Sopenharmony_ci } else { 452353a5a1b3Sopenharmony_ci 452453a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SUSPEND_SOURCE); 452553a5a1b3Sopenharmony_ci 452653a5a1b3Sopenharmony_ci if (idx == PA_INVALID_INDEX && name && !*name) { 452753a5a1b3Sopenharmony_ci 452853a5a1b3Sopenharmony_ci pa_log_debug("%s all sources", b ? "Suspending" : "Resuming"); 452953a5a1b3Sopenharmony_ci 453053a5a1b3Sopenharmony_ci if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) { 453153a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 453253a5a1b3Sopenharmony_ci return; 453353a5a1b3Sopenharmony_ci } 453453a5a1b3Sopenharmony_ci 453553a5a1b3Sopenharmony_ci } else { 453653a5a1b3Sopenharmony_ci pa_source *source; 453753a5a1b3Sopenharmony_ci 453853a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 453953a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx); 454053a5a1b3Sopenharmony_ci else 454153a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); 454253a5a1b3Sopenharmony_ci 454353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); 454453a5a1b3Sopenharmony_ci 454553a5a1b3Sopenharmony_ci pa_log_debug("%s of source %s requested by client %" PRIu32 ".", 454653a5a1b3Sopenharmony_ci b ? "Suspending" : "Resuming", source->name, c->client->index); 454753a5a1b3Sopenharmony_ci 454853a5a1b3Sopenharmony_ci if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) { 454953a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); 455053a5a1b3Sopenharmony_ci return; 455153a5a1b3Sopenharmony_ci } 455253a5a1b3Sopenharmony_ci } 455353a5a1b3Sopenharmony_ci } 455453a5a1b3Sopenharmony_ci 455553a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 455653a5a1b3Sopenharmony_ci} 455753a5a1b3Sopenharmony_ci 455853a5a1b3Sopenharmony_cistatic void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 455953a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 456053a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX; 456153a5a1b3Sopenharmony_ci const char *name = NULL; 456253a5a1b3Sopenharmony_ci pa_module *m; 456353a5a1b3Sopenharmony_ci pa_native_protocol_ext_cb_t cb; 456453a5a1b3Sopenharmony_ci 456553a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 456653a5a1b3Sopenharmony_ci pa_assert(t); 456753a5a1b3Sopenharmony_ci 456853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 456953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0) { 457053a5a1b3Sopenharmony_ci protocol_error(c); 457153a5a1b3Sopenharmony_ci return; 457253a5a1b3Sopenharmony_ci } 457353a5a1b3Sopenharmony_ci 457453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 457553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID); 457653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 457753a5a1b3Sopenharmony_ci 457853a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 457953a5a1b3Sopenharmony_ci m = pa_idxset_get_by_index(c->protocol->core->modules, idx); 458053a5a1b3Sopenharmony_ci else 458153a5a1b3Sopenharmony_ci PA_IDXSET_FOREACH(m, c->protocol->core->modules, idx) 458253a5a1b3Sopenharmony_ci if (pa_streq(name, m->name)) 458353a5a1b3Sopenharmony_ci break; 458453a5a1b3Sopenharmony_ci 458553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOEXTENSION); 458653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, m->load_once || idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); 458753a5a1b3Sopenharmony_ci 458853a5a1b3Sopenharmony_ci cb = pa_hashmap_get(c->protocol->extensions, m); 458953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, cb, tag, PA_ERR_NOEXTENSION); 459053a5a1b3Sopenharmony_ci 459153a5a1b3Sopenharmony_ci if (cb(c->protocol, m, c, tag, t) < 0) 459253a5a1b3Sopenharmony_ci protocol_error(c); 459353a5a1b3Sopenharmony_ci} 459453a5a1b3Sopenharmony_ci 459553a5a1b3Sopenharmony_ci/* Send message to an object which registered a handler. Result must be returned as string. */ 459653a5a1b3Sopenharmony_cistatic void command_send_object_message(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 459753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 459853a5a1b3Sopenharmony_ci const char *object_path = NULL; 459953a5a1b3Sopenharmony_ci const char *message = NULL; 460053a5a1b3Sopenharmony_ci const char *message_parameters = NULL; 460153a5a1b3Sopenharmony_ci const char *client_name; 460253a5a1b3Sopenharmony_ci char *response = NULL; 460353a5a1b3Sopenharmony_ci int ret; 460453a5a1b3Sopenharmony_ci pa_tagstruct *reply; 460553a5a1b3Sopenharmony_ci 460653a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 460753a5a1b3Sopenharmony_ci pa_assert(t); 460853a5a1b3Sopenharmony_ci 460953a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &object_path) < 0 || 461053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &message) < 0 || 461153a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &message_parameters) < 0 || 461253a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 461353a5a1b3Sopenharmony_ci protocol_error(c); 461453a5a1b3Sopenharmony_ci return; 461553a5a1b3Sopenharmony_ci } 461653a5a1b3Sopenharmony_ci 461753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 461853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, object_path != NULL, tag, PA_ERR_INVALID); 461953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_utf8_valid(object_path), tag, PA_ERR_INVALID); 462053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, message != NULL, tag, PA_ERR_INVALID); 462153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_utf8_valid(message), tag, PA_ERR_INVALID); 462253a5a1b3Sopenharmony_ci if (message_parameters) 462353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, pa_utf8_valid(message_parameters), tag, PA_ERR_INVALID); 462453a5a1b3Sopenharmony_ci 462553a5a1b3Sopenharmony_ci client_name = pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_PROCESS_BINARY)); 462653a5a1b3Sopenharmony_ci pa_log_debug("Client %s sent message %s to path %s", client_name, message, object_path); 462753a5a1b3Sopenharmony_ci if (message_parameters) 462853a5a1b3Sopenharmony_ci pa_log_debug("Message parameters: %s", message_parameters); 462953a5a1b3Sopenharmony_ci 463053a5a1b3Sopenharmony_ci ret = pa_message_handler_send_message(c->protocol->core, object_path, message, message_parameters, &response); 463153a5a1b3Sopenharmony_ci 463253a5a1b3Sopenharmony_ci if (ret < 0) { 463353a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, -ret); 463453a5a1b3Sopenharmony_ci return; 463553a5a1b3Sopenharmony_ci } 463653a5a1b3Sopenharmony_ci 463753a5a1b3Sopenharmony_ci reply = reply_new(tag); 463853a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, response); 463953a5a1b3Sopenharmony_ci pa_xfree(response); 464053a5a1b3Sopenharmony_ci 464153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 464253a5a1b3Sopenharmony_ci} 464353a5a1b3Sopenharmony_ci 464453a5a1b3Sopenharmony_cistatic void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 464553a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 464653a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX; 464753a5a1b3Sopenharmony_ci const char *name = NULL, *profile_name = NULL; 464853a5a1b3Sopenharmony_ci pa_card *card = NULL; 464953a5a1b3Sopenharmony_ci pa_card_profile *profile; 465053a5a1b3Sopenharmony_ci int ret; 465153a5a1b3Sopenharmony_ci 465253a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 465353a5a1b3Sopenharmony_ci pa_assert(t); 465453a5a1b3Sopenharmony_ci 465553a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 465653a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 465753a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &profile_name) < 0 || 465853a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 465953a5a1b3Sopenharmony_ci protocol_error(c); 466053a5a1b3Sopenharmony_ci return; 466153a5a1b3Sopenharmony_ci } 466253a5a1b3Sopenharmony_ci 466353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 466453a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); 466553a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 466653a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, profile_name, tag, PA_ERR_INVALID); 466753a5a1b3Sopenharmony_ci 466853a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 466953a5a1b3Sopenharmony_ci card = pa_idxset_get_by_index(c->protocol->core->cards, idx); 467053a5a1b3Sopenharmony_ci else 467153a5a1b3Sopenharmony_ci card = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_CARD); 467253a5a1b3Sopenharmony_ci 467353a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY); 467453a5a1b3Sopenharmony_ci 467553a5a1b3Sopenharmony_ci profile = pa_hashmap_get(card->profiles, profile_name); 467653a5a1b3Sopenharmony_ci 467753a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, profile, tag, PA_ERR_NOENTITY); 467853a5a1b3Sopenharmony_ci 467953a5a1b3Sopenharmony_ci pa_log_info("Application \"%s\" requests card profile change. card = %s, profile = %s", 468053a5a1b3Sopenharmony_ci pa_strnull(pa_proplist_gets(c->client->proplist, PA_PROP_APPLICATION_NAME)), 468153a5a1b3Sopenharmony_ci card->name, 468253a5a1b3Sopenharmony_ci profile->name); 468353a5a1b3Sopenharmony_ci 468453a5a1b3Sopenharmony_ci if ((ret = pa_card_set_profile(card, profile, true)) < 0) { 468553a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, -ret); 468653a5a1b3Sopenharmony_ci return; 468753a5a1b3Sopenharmony_ci } 468853a5a1b3Sopenharmony_ci 468953a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 469053a5a1b3Sopenharmony_ci} 469153a5a1b3Sopenharmony_ci 469253a5a1b3Sopenharmony_cistatic void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 469353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 469453a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX; 469553a5a1b3Sopenharmony_ci const char *name = NULL, *port = NULL; 469653a5a1b3Sopenharmony_ci int ret; 469753a5a1b3Sopenharmony_ci 469853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 469953a5a1b3Sopenharmony_ci pa_assert(t); 470053a5a1b3Sopenharmony_ci 470153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 470253a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 470353a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &port) < 0 || 470453a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 470553a5a1b3Sopenharmony_ci protocol_error(c); 470653a5a1b3Sopenharmony_ci return; 470753a5a1b3Sopenharmony_ci } 470853a5a1b3Sopenharmony_ci 470953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 471053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name_or_wildcard(name, command == PA_COMMAND_SET_SINK_PORT ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE), tag, PA_ERR_INVALID); 471153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (name != NULL), tag, PA_ERR_INVALID); 471253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_INVALID); 471353a5a1b3Sopenharmony_ci 471453a5a1b3Sopenharmony_ci if (command == PA_COMMAND_SET_SINK_PORT) { 471553a5a1b3Sopenharmony_ci pa_sink *sink; 471653a5a1b3Sopenharmony_ci 471753a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 471853a5a1b3Sopenharmony_ci sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); 471953a5a1b3Sopenharmony_ci else 472053a5a1b3Sopenharmony_ci sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); 472153a5a1b3Sopenharmony_ci 472253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); 472353a5a1b3Sopenharmony_ci 472453a5a1b3Sopenharmony_ci if ((ret = pa_sink_set_port(sink, port, true)) < 0) { 472553a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, -ret); 472653a5a1b3Sopenharmony_ci return; 472753a5a1b3Sopenharmony_ci } 472853a5a1b3Sopenharmony_ci } else { 472953a5a1b3Sopenharmony_ci pa_source *source; 473053a5a1b3Sopenharmony_ci 473153a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SET_SOURCE_PORT); 473253a5a1b3Sopenharmony_ci 473353a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 473453a5a1b3Sopenharmony_ci source = pa_idxset_get_by_index(c->protocol->core->sources, idx); 473553a5a1b3Sopenharmony_ci else 473653a5a1b3Sopenharmony_ci source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); 473753a5a1b3Sopenharmony_ci 473853a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); 473953a5a1b3Sopenharmony_ci 474053a5a1b3Sopenharmony_ci if ((ret = pa_source_set_port(source, port, true)) < 0) { 474153a5a1b3Sopenharmony_ci pa_pstream_send_error(c->pstream, tag, -ret); 474253a5a1b3Sopenharmony_ci return; 474353a5a1b3Sopenharmony_ci } 474453a5a1b3Sopenharmony_ci } 474553a5a1b3Sopenharmony_ci 474653a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 474753a5a1b3Sopenharmony_ci} 474853a5a1b3Sopenharmony_ci 474953a5a1b3Sopenharmony_cistatic void command_set_port_latency_offset(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 475053a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 475153a5a1b3Sopenharmony_ci const char *port_name, *card_name; 475253a5a1b3Sopenharmony_ci uint32_t idx = PA_INVALID_INDEX; 475353a5a1b3Sopenharmony_ci int64_t offset; 475453a5a1b3Sopenharmony_ci pa_card *card = NULL; 475553a5a1b3Sopenharmony_ci pa_device_port *port = NULL; 475653a5a1b3Sopenharmony_ci 475753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 475853a5a1b3Sopenharmony_ci pa_assert(t); 475953a5a1b3Sopenharmony_ci 476053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 476153a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &card_name) < 0 || 476253a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &port_name) < 0 || 476353a5a1b3Sopenharmony_ci pa_tagstruct_gets64(t, &offset) < 0 || 476453a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 476553a5a1b3Sopenharmony_ci protocol_error(c); 476653a5a1b3Sopenharmony_ci return; 476753a5a1b3Sopenharmony_ci } 476853a5a1b3Sopenharmony_ci 476953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); 477053a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, !card_name || pa_namereg_is_valid_name(card_name), tag, PA_ERR_INVALID); 477153a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, (idx != PA_INVALID_INDEX) ^ (card_name != NULL), tag, PA_ERR_INVALID); 477253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, port_name, tag, PA_ERR_INVALID); 477353a5a1b3Sopenharmony_ci 477453a5a1b3Sopenharmony_ci if (idx != PA_INVALID_INDEX) 477553a5a1b3Sopenharmony_ci card = pa_idxset_get_by_index(c->protocol->core->cards, idx); 477653a5a1b3Sopenharmony_ci else 477753a5a1b3Sopenharmony_ci card = pa_namereg_get(c->protocol->core, card_name, PA_NAMEREG_CARD); 477853a5a1b3Sopenharmony_ci 477953a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY); 478053a5a1b3Sopenharmony_ci 478153a5a1b3Sopenharmony_ci port = pa_hashmap_get(card->ports, port_name); 478253a5a1b3Sopenharmony_ci CHECK_VALIDITY(c->pstream, port, tag, PA_ERR_NOENTITY); 478353a5a1b3Sopenharmony_ci 478453a5a1b3Sopenharmony_ci pa_device_port_set_latency_offset(port, offset); 478553a5a1b3Sopenharmony_ci 478653a5a1b3Sopenharmony_ci pa_pstream_send_simple_ack(c->pstream, tag); 478753a5a1b3Sopenharmony_ci} 478853a5a1b3Sopenharmony_ci 478953a5a1b3Sopenharmony_cistatic const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { 479053a5a1b3Sopenharmony_ci [PA_COMMAND_ERROR] = NULL, 479153a5a1b3Sopenharmony_ci [PA_COMMAND_TIMEOUT] = NULL, 479253a5a1b3Sopenharmony_ci [PA_COMMAND_REPLY] = NULL, 479353a5a1b3Sopenharmony_ci [PA_COMMAND_CREATE_PLAYBACK_STREAM] = command_create_playback_stream, 479453a5a1b3Sopenharmony_ci [PA_COMMAND_DELETE_PLAYBACK_STREAM] = command_delete_stream, 479553a5a1b3Sopenharmony_ci [PA_COMMAND_DRAIN_PLAYBACK_STREAM] = command_drain_playback_stream, 479653a5a1b3Sopenharmony_ci [PA_COMMAND_CREATE_RECORD_STREAM] = command_create_record_stream, 479753a5a1b3Sopenharmony_ci [PA_COMMAND_DELETE_RECORD_STREAM] = command_delete_stream, 479853a5a1b3Sopenharmony_ci [PA_COMMAND_AUTH] = command_auth, 479953a5a1b3Sopenharmony_ci [PA_COMMAND_REQUEST] = NULL, 480053a5a1b3Sopenharmony_ci [PA_COMMAND_EXIT] = command_exit, 480153a5a1b3Sopenharmony_ci [PA_COMMAND_SET_CLIENT_NAME] = command_set_client_name, 480253a5a1b3Sopenharmony_ci [PA_COMMAND_LOOKUP_SINK] = command_lookup, 480353a5a1b3Sopenharmony_ci [PA_COMMAND_LOOKUP_SOURCE] = command_lookup, 480453a5a1b3Sopenharmony_ci [PA_COMMAND_STAT] = command_stat, 480553a5a1b3Sopenharmony_ci [PA_COMMAND_GET_PLAYBACK_LATENCY] = command_get_playback_latency, 480653a5a1b3Sopenharmony_ci [PA_COMMAND_GET_RECORD_LATENCY] = command_get_record_latency, 480753a5a1b3Sopenharmony_ci [PA_COMMAND_CREATE_UPLOAD_STREAM] = command_create_upload_stream, 480853a5a1b3Sopenharmony_ci [PA_COMMAND_DELETE_UPLOAD_STREAM] = command_delete_stream, 480953a5a1b3Sopenharmony_ci [PA_COMMAND_FINISH_UPLOAD_STREAM] = command_finish_upload_stream, 481053a5a1b3Sopenharmony_ci [PA_COMMAND_PLAY_SAMPLE] = command_play_sample, 481153a5a1b3Sopenharmony_ci [PA_COMMAND_REMOVE_SAMPLE] = command_remove_sample, 481253a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SINK_INFO] = command_get_info, 481353a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SOURCE_INFO] = command_get_info, 481453a5a1b3Sopenharmony_ci [PA_COMMAND_GET_CLIENT_INFO] = command_get_info, 481553a5a1b3Sopenharmony_ci [PA_COMMAND_GET_CARD_INFO] = command_get_info, 481653a5a1b3Sopenharmony_ci [PA_COMMAND_GET_MODULE_INFO] = command_get_info, 481753a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SINK_INPUT_INFO] = command_get_info, 481853a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SOURCE_OUTPUT_INFO] = command_get_info, 481953a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SAMPLE_INFO] = command_get_info, 482053a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SINK_INFO_LIST] = command_get_info_list, 482153a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SOURCE_INFO_LIST] = command_get_info_list, 482253a5a1b3Sopenharmony_ci [PA_COMMAND_GET_MODULE_INFO_LIST] = command_get_info_list, 482353a5a1b3Sopenharmony_ci [PA_COMMAND_GET_CLIENT_INFO_LIST] = command_get_info_list, 482453a5a1b3Sopenharmony_ci [PA_COMMAND_GET_CARD_INFO_LIST] = command_get_info_list, 482553a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SINK_INPUT_INFO_LIST] = command_get_info_list, 482653a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST] = command_get_info_list, 482753a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SAMPLE_INFO_LIST] = command_get_info_list, 482853a5a1b3Sopenharmony_ci [PA_COMMAND_GET_SERVER_INFO] = command_get_server_info, 482953a5a1b3Sopenharmony_ci [PA_COMMAND_SUBSCRIBE] = command_subscribe, 483053a5a1b3Sopenharmony_ci 483153a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SINK_VOLUME] = command_set_volume, 483253a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SINK_INPUT_VOLUME] = command_set_volume, 483353a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SOURCE_VOLUME] = command_set_volume, 483453a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SOURCE_OUTPUT_VOLUME] = command_set_volume, 483553a5a1b3Sopenharmony_ci 483653a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SINK_MUTE] = command_set_mute, 483753a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SINK_INPUT_MUTE] = command_set_mute, 483853a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SOURCE_MUTE] = command_set_mute, 483953a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SOURCE_OUTPUT_MUTE] = command_set_mute, 484053a5a1b3Sopenharmony_ci 484153a5a1b3Sopenharmony_ci [PA_COMMAND_SUSPEND_SINK] = command_suspend, 484253a5a1b3Sopenharmony_ci [PA_COMMAND_SUSPEND_SOURCE] = command_suspend, 484353a5a1b3Sopenharmony_ci 484453a5a1b3Sopenharmony_ci [PA_COMMAND_CORK_PLAYBACK_STREAM] = command_cork_playback_stream, 484553a5a1b3Sopenharmony_ci [PA_COMMAND_FLUSH_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, 484653a5a1b3Sopenharmony_ci [PA_COMMAND_TRIGGER_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, 484753a5a1b3Sopenharmony_ci [PA_COMMAND_PREBUF_PLAYBACK_STREAM] = command_trigger_or_flush_or_prebuf_playback_stream, 484853a5a1b3Sopenharmony_ci 484953a5a1b3Sopenharmony_ci [PA_COMMAND_CORK_RECORD_STREAM] = command_cork_record_stream, 485053a5a1b3Sopenharmony_ci [PA_COMMAND_FLUSH_RECORD_STREAM] = command_flush_record_stream, 485153a5a1b3Sopenharmony_ci 485253a5a1b3Sopenharmony_ci [PA_COMMAND_SET_DEFAULT_SINK] = command_set_default_sink_or_source, 485353a5a1b3Sopenharmony_ci [PA_COMMAND_SET_DEFAULT_SOURCE] = command_set_default_sink_or_source, 485453a5a1b3Sopenharmony_ci [PA_COMMAND_SET_PLAYBACK_STREAM_NAME] = command_set_stream_name, 485553a5a1b3Sopenharmony_ci [PA_COMMAND_SET_RECORD_STREAM_NAME] = command_set_stream_name, 485653a5a1b3Sopenharmony_ci [PA_COMMAND_KILL_CLIENT] = command_kill, 485753a5a1b3Sopenharmony_ci [PA_COMMAND_KILL_SINK_INPUT] = command_kill, 485853a5a1b3Sopenharmony_ci [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, 485953a5a1b3Sopenharmony_ci [PA_COMMAND_LOAD_MODULE] = command_load_module, 486053a5a1b3Sopenharmony_ci [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, 486153a5a1b3Sopenharmony_ci 486253a5a1b3Sopenharmony_ci [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL, 486353a5a1b3Sopenharmony_ci [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL, 486453a5a1b3Sopenharmony_ci [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL, 486553a5a1b3Sopenharmony_ci [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL, 486653a5a1b3Sopenharmony_ci 486753a5a1b3Sopenharmony_ci [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream, 486853a5a1b3Sopenharmony_ci [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream, 486953a5a1b3Sopenharmony_ci 487053a5a1b3Sopenharmony_ci [PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr, 487153a5a1b3Sopenharmony_ci [PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR] = command_set_stream_buffer_attr, 487253a5a1b3Sopenharmony_ci 487353a5a1b3Sopenharmony_ci [PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate, 487453a5a1b3Sopenharmony_ci [PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE] = command_update_stream_sample_rate, 487553a5a1b3Sopenharmony_ci 487653a5a1b3Sopenharmony_ci [PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST] = command_update_proplist, 487753a5a1b3Sopenharmony_ci [PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST] = command_update_proplist, 487853a5a1b3Sopenharmony_ci [PA_COMMAND_UPDATE_CLIENT_PROPLIST] = command_update_proplist, 487953a5a1b3Sopenharmony_ci 488053a5a1b3Sopenharmony_ci [PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST] = command_remove_proplist, 488153a5a1b3Sopenharmony_ci [PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST] = command_remove_proplist, 488253a5a1b3Sopenharmony_ci [PA_COMMAND_REMOVE_CLIENT_PROPLIST] = command_remove_proplist, 488353a5a1b3Sopenharmony_ci 488453a5a1b3Sopenharmony_ci [PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile, 488553a5a1b3Sopenharmony_ci 488653a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port, 488753a5a1b3Sopenharmony_ci [PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port, 488853a5a1b3Sopenharmony_ci 488953a5a1b3Sopenharmony_ci [PA_COMMAND_SET_PORT_LATENCY_OFFSET] = command_set_port_latency_offset, 489053a5a1b3Sopenharmony_ci 489153a5a1b3Sopenharmony_ci [PA_COMMAND_ENABLE_SRBCHANNEL] = command_enable_srbchannel, 489253a5a1b3Sopenharmony_ci 489353a5a1b3Sopenharmony_ci [PA_COMMAND_REGISTER_MEMFD_SHMID] = command_register_memfd_shmid, 489453a5a1b3Sopenharmony_ci 489553a5a1b3Sopenharmony_ci [PA_COMMAND_SEND_OBJECT_MESSAGE] = command_send_object_message, 489653a5a1b3Sopenharmony_ci 489753a5a1b3Sopenharmony_ci [PA_COMMAND_EXTENSION] = command_extension 489853a5a1b3Sopenharmony_ci}; 489953a5a1b3Sopenharmony_ci 490053a5a1b3Sopenharmony_ci/*** pstream callbacks ***/ 490153a5a1b3Sopenharmony_ci 490253a5a1b3Sopenharmony_cistatic void pstream_packet_callback(pa_pstream *p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) { 490353a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 490453a5a1b3Sopenharmony_ci 490553a5a1b3Sopenharmony_ci pa_assert(p); 490653a5a1b3Sopenharmony_ci pa_assert(packet); 490753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 490853a5a1b3Sopenharmony_ci 490953a5a1b3Sopenharmony_ci if (pa_pdispatch_run(c->pdispatch, packet, ancil_data, c) < 0) { 491053a5a1b3Sopenharmony_ci pa_log("invalid packet."); 491153a5a1b3Sopenharmony_ci native_connection_unlink(c); 491253a5a1b3Sopenharmony_ci } 491353a5a1b3Sopenharmony_ci} 491453a5a1b3Sopenharmony_ci 491553a5a1b3Sopenharmony_cistatic void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { 491653a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 491753a5a1b3Sopenharmony_ci output_stream *stream; 491853a5a1b3Sopenharmony_ci 491953a5a1b3Sopenharmony_ci pa_assert(p); 492053a5a1b3Sopenharmony_ci pa_assert(chunk); 492153a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 492253a5a1b3Sopenharmony_ci 492353a5a1b3Sopenharmony_ci if (!(stream = OUTPUT_STREAM(pa_idxset_get_by_index(c->output_streams, channel)))) { 492453a5a1b3Sopenharmony_ci pa_log_debug("Client sent block for invalid stream."); 492553a5a1b3Sopenharmony_ci /* Ignoring */ 492653a5a1b3Sopenharmony_ci return; 492753a5a1b3Sopenharmony_ci } 492853a5a1b3Sopenharmony_ci 492953a5a1b3Sopenharmony_ci#ifdef PROTOCOL_NATIVE_DEBUG 493053a5a1b3Sopenharmony_ci pa_log("got %lu bytes from client", (unsigned long) chunk->length); 493153a5a1b3Sopenharmony_ci#endif 493253a5a1b3Sopenharmony_ci 493353a5a1b3Sopenharmony_ci if (playback_stream_isinstance(stream)) { 493453a5a1b3Sopenharmony_ci playback_stream *ps = PLAYBACK_STREAM(stream); 493553a5a1b3Sopenharmony_ci 493653a5a1b3Sopenharmony_ci size_t frame_size = pa_frame_size(&ps->sink_input->sample_spec); 493753a5a1b3Sopenharmony_ci if (chunk->index % frame_size != 0 || chunk->length % frame_size != 0) { 493853a5a1b3Sopenharmony_ci pa_log_warn("Client sent non-aligned memblock: index %d, length %d, frame size:" 493953a5a1b3Sopenharmony_ci "%d", (int) chunk->index, (int) chunk->length, (int) frame_size); 494053a5a1b3Sopenharmony_ci return; 494153a5a1b3Sopenharmony_ci } 494253a5a1b3Sopenharmony_ci 494353a5a1b3Sopenharmony_ci pa_atomic_inc(&ps->seek_or_post_in_queue); 494453a5a1b3Sopenharmony_ci if (chunk->memblock) { 494553a5a1b3Sopenharmony_ci if (seek != PA_SEEK_RELATIVE || offset != 0) 494653a5a1b3Sopenharmony_ci pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset, chunk, NULL); 494753a5a1b3Sopenharmony_ci else 494853a5a1b3Sopenharmony_ci pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_POST_DATA, NULL, 0, chunk, NULL); 494953a5a1b3Sopenharmony_ci } else 495053a5a1b3Sopenharmony_ci pa_asyncmsgq_post(ps->sink_input->sink->asyncmsgq, PA_MSGOBJECT(ps->sink_input), SINK_INPUT_MESSAGE_SEEK, PA_UINT_TO_PTR(seek), offset+chunk->length, NULL, NULL); 495153a5a1b3Sopenharmony_ci 495253a5a1b3Sopenharmony_ci } else { 495353a5a1b3Sopenharmony_ci upload_stream *u = UPLOAD_STREAM(stream); 495453a5a1b3Sopenharmony_ci size_t l; 495553a5a1b3Sopenharmony_ci 495653a5a1b3Sopenharmony_ci if (!u->memchunk.memblock) { 495753a5a1b3Sopenharmony_ci if (u->length == chunk->length && chunk->memblock) { 495853a5a1b3Sopenharmony_ci u->memchunk = *chunk; 495953a5a1b3Sopenharmony_ci pa_memblock_ref(u->memchunk.memblock); 496053a5a1b3Sopenharmony_ci u->length = 0; 496153a5a1b3Sopenharmony_ci } else { 496253a5a1b3Sopenharmony_ci u->memchunk.memblock = pa_memblock_new(c->protocol->core->mempool, u->length); 496353a5a1b3Sopenharmony_ci u->memchunk.index = u->memchunk.length = 0; 496453a5a1b3Sopenharmony_ci } 496553a5a1b3Sopenharmony_ci } 496653a5a1b3Sopenharmony_ci 496753a5a1b3Sopenharmony_ci pa_assert(u->memchunk.memblock); 496853a5a1b3Sopenharmony_ci 496953a5a1b3Sopenharmony_ci l = u->length; 497053a5a1b3Sopenharmony_ci if (l > chunk->length) 497153a5a1b3Sopenharmony_ci l = chunk->length; 497253a5a1b3Sopenharmony_ci 497353a5a1b3Sopenharmony_ci if (l > 0) { 497453a5a1b3Sopenharmony_ci void *dst; 497553a5a1b3Sopenharmony_ci dst = pa_memblock_acquire(u->memchunk.memblock); 497653a5a1b3Sopenharmony_ci 497753a5a1b3Sopenharmony_ci if (chunk->memblock) { 497853a5a1b3Sopenharmony_ci void *src; 497953a5a1b3Sopenharmony_ci src = pa_memblock_acquire(chunk->memblock); 498053a5a1b3Sopenharmony_ci 498153a5a1b3Sopenharmony_ci memcpy((uint8_t*) dst + u->memchunk.index + u->memchunk.length, 498253a5a1b3Sopenharmony_ci (uint8_t*) src + chunk->index, l); 498353a5a1b3Sopenharmony_ci 498453a5a1b3Sopenharmony_ci pa_memblock_release(chunk->memblock); 498553a5a1b3Sopenharmony_ci } else 498653a5a1b3Sopenharmony_ci pa_silence_memory((uint8_t*) dst + u->memchunk.index + u->memchunk.length, l, &u->sample_spec); 498753a5a1b3Sopenharmony_ci 498853a5a1b3Sopenharmony_ci pa_memblock_release(u->memchunk.memblock); 498953a5a1b3Sopenharmony_ci 499053a5a1b3Sopenharmony_ci u->memchunk.length += l; 499153a5a1b3Sopenharmony_ci u->length -= l; 499253a5a1b3Sopenharmony_ci } 499353a5a1b3Sopenharmony_ci } 499453a5a1b3Sopenharmony_ci} 499553a5a1b3Sopenharmony_ci 499653a5a1b3Sopenharmony_cistatic void pstream_die_callback(pa_pstream *p, void *userdata) { 499753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 499853a5a1b3Sopenharmony_ci 499953a5a1b3Sopenharmony_ci pa_assert(p); 500053a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 500153a5a1b3Sopenharmony_ci 500253a5a1b3Sopenharmony_ci native_connection_unlink(c); 500353a5a1b3Sopenharmony_ci pa_log_info("Connection died."); 500453a5a1b3Sopenharmony_ci} 500553a5a1b3Sopenharmony_ci 500653a5a1b3Sopenharmony_cistatic void pstream_drain_callback(pa_pstream *p, void *userdata) { 500753a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 500853a5a1b3Sopenharmony_ci 500953a5a1b3Sopenharmony_ci pa_assert(p); 501053a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 501153a5a1b3Sopenharmony_ci 501253a5a1b3Sopenharmony_ci native_connection_send_memblock(c); 501353a5a1b3Sopenharmony_ci} 501453a5a1b3Sopenharmony_ci 501553a5a1b3Sopenharmony_cistatic void pstream_revoke_callback(pa_pstream *p, uint32_t block_id, void *userdata) { 501653a5a1b3Sopenharmony_ci pa_thread_mq *q; 501753a5a1b3Sopenharmony_ci 501853a5a1b3Sopenharmony_ci if (!(q = pa_thread_mq_get())) 501953a5a1b3Sopenharmony_ci pa_pstream_send_revoke(p, block_id); 502053a5a1b3Sopenharmony_ci else 502153a5a1b3Sopenharmony_ci pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_REVOKE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL); 502253a5a1b3Sopenharmony_ci} 502353a5a1b3Sopenharmony_ci 502453a5a1b3Sopenharmony_cistatic void pstream_release_callback(pa_pstream *p, uint32_t block_id, void *userdata) { 502553a5a1b3Sopenharmony_ci pa_thread_mq *q; 502653a5a1b3Sopenharmony_ci 502753a5a1b3Sopenharmony_ci if (!(q = pa_thread_mq_get())) 502853a5a1b3Sopenharmony_ci pa_pstream_send_release(p, block_id); 502953a5a1b3Sopenharmony_ci else 503053a5a1b3Sopenharmony_ci pa_asyncmsgq_post(q->outq, PA_MSGOBJECT(userdata), CONNECTION_MESSAGE_RELEASE, PA_UINT_TO_PTR(block_id), 0, NULL, NULL); 503153a5a1b3Sopenharmony_ci} 503253a5a1b3Sopenharmony_ci 503353a5a1b3Sopenharmony_ci/*** client callbacks ***/ 503453a5a1b3Sopenharmony_ci 503553a5a1b3Sopenharmony_cistatic void client_kill_cb(pa_client *c) { 503653a5a1b3Sopenharmony_ci pa_assert(c); 503753a5a1b3Sopenharmony_ci 503853a5a1b3Sopenharmony_ci native_connection_unlink(PA_NATIVE_CONNECTION(c->userdata)); 503953a5a1b3Sopenharmony_ci pa_log_info("Connection killed."); 504053a5a1b3Sopenharmony_ci} 504153a5a1b3Sopenharmony_ci 504253a5a1b3Sopenharmony_cistatic void client_send_event_cb(pa_client *client, const char*event, pa_proplist *pl) { 504353a5a1b3Sopenharmony_ci pa_tagstruct *t; 504453a5a1b3Sopenharmony_ci pa_native_connection *c; 504553a5a1b3Sopenharmony_ci 504653a5a1b3Sopenharmony_ci pa_assert(client); 504753a5a1b3Sopenharmony_ci c = PA_NATIVE_CONNECTION(client->userdata); 504853a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 504953a5a1b3Sopenharmony_ci 505053a5a1b3Sopenharmony_ci if (c->version < 15) 505153a5a1b3Sopenharmony_ci return; 505253a5a1b3Sopenharmony_ci 505353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 505453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_CLIENT_EVENT); 505553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */ 505653a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, event); 505753a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, pl); 505853a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 505953a5a1b3Sopenharmony_ci} 506053a5a1b3Sopenharmony_ci 506153a5a1b3Sopenharmony_ci/*** module entry points ***/ 506253a5a1b3Sopenharmony_ci 506353a5a1b3Sopenharmony_cistatic void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) { 506453a5a1b3Sopenharmony_ci pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); 506553a5a1b3Sopenharmony_ci 506653a5a1b3Sopenharmony_ci pa_assert(m); 506753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 506853a5a1b3Sopenharmony_ci pa_assert(c->auth_timeout_event == e); 506953a5a1b3Sopenharmony_ci 507053a5a1b3Sopenharmony_ci if (!c->authorized) { 507153a5a1b3Sopenharmony_ci native_connection_unlink(c); 507253a5a1b3Sopenharmony_ci pa_log_info("Connection terminated due to authentication timeout."); 507353a5a1b3Sopenharmony_ci } 507453a5a1b3Sopenharmony_ci} 507553a5a1b3Sopenharmony_ci 507653a5a1b3Sopenharmony_civoid pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) { 507753a5a1b3Sopenharmony_ci pa_native_connection *c; 507853a5a1b3Sopenharmony_ci char pname[128]; 507953a5a1b3Sopenharmony_ci pa_client *client; 508053a5a1b3Sopenharmony_ci pa_client_new_data data; 508153a5a1b3Sopenharmony_ci 508253a5a1b3Sopenharmony_ci pa_assert(p); 508353a5a1b3Sopenharmony_ci pa_assert(io); 508453a5a1b3Sopenharmony_ci pa_assert(o); 508553a5a1b3Sopenharmony_ci 508653a5a1b3Sopenharmony_ci if (pa_idxset_size(p->connections)+1 > MAX_CONNECTIONS) { 508753a5a1b3Sopenharmony_ci pa_log_warn("Warning! Too many connections (%u), dropping incoming connection.", MAX_CONNECTIONS); 508853a5a1b3Sopenharmony_ci pa_iochannel_free(io); 508953a5a1b3Sopenharmony_ci return; 509053a5a1b3Sopenharmony_ci } 509153a5a1b3Sopenharmony_ci 509253a5a1b3Sopenharmony_ci pa_client_new_data_init(&data); 509353a5a1b3Sopenharmony_ci data.module = o->module; 509453a5a1b3Sopenharmony_ci data.driver = __FILE__; 509553a5a1b3Sopenharmony_ci pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); 509653a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname); 509753a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, "native-protocol.peer", pname); 509853a5a1b3Sopenharmony_ci client = pa_client_new(p->core, &data); 509953a5a1b3Sopenharmony_ci pa_client_new_data_done(&data); 510053a5a1b3Sopenharmony_ci 510153a5a1b3Sopenharmony_ci if (!client) 510253a5a1b3Sopenharmony_ci return; 510353a5a1b3Sopenharmony_ci 510453a5a1b3Sopenharmony_ci c = pa_msgobject_new(pa_native_connection); 510553a5a1b3Sopenharmony_ci c->parent.parent.free = native_connection_free; 510653a5a1b3Sopenharmony_ci c->parent.process_msg = native_connection_process_msg; 510753a5a1b3Sopenharmony_ci c->protocol = p; 510853a5a1b3Sopenharmony_ci c->options = pa_native_options_ref(o); 510953a5a1b3Sopenharmony_ci c->authorized = false; 511053a5a1b3Sopenharmony_ci c->srbpending = NULL; 511153a5a1b3Sopenharmony_ci 511253a5a1b3Sopenharmony_ci if (o->auth_anonymous) { 511353a5a1b3Sopenharmony_ci pa_log_info("Client authenticated anonymously."); 511453a5a1b3Sopenharmony_ci c->authorized = true; 511553a5a1b3Sopenharmony_ci } 511653a5a1b3Sopenharmony_ci 511753a5a1b3Sopenharmony_ci if (!c->authorized && 511853a5a1b3Sopenharmony_ci o->auth_ip_acl && 511953a5a1b3Sopenharmony_ci pa_ip_acl_check(o->auth_ip_acl, pa_iochannel_get_recv_fd(io)) > 0) { 512053a5a1b3Sopenharmony_ci 512153a5a1b3Sopenharmony_ci pa_log_info("Client authenticated by IP ACL."); 512253a5a1b3Sopenharmony_ci c->authorized = true; 512353a5a1b3Sopenharmony_ci } 512453a5a1b3Sopenharmony_ci 512553a5a1b3Sopenharmony_ci if (!c->authorized) 512653a5a1b3Sopenharmony_ci c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c); 512753a5a1b3Sopenharmony_ci else 512853a5a1b3Sopenharmony_ci c->auth_timeout_event = NULL; 512953a5a1b3Sopenharmony_ci 513053a5a1b3Sopenharmony_ci c->is_local = pa_iochannel_socket_is_local(io); 513153a5a1b3Sopenharmony_ci c->version = 8; 513253a5a1b3Sopenharmony_ci 513353a5a1b3Sopenharmony_ci c->client = client; 513453a5a1b3Sopenharmony_ci c->client->kill = client_kill_cb; 513553a5a1b3Sopenharmony_ci c->client->send_event = client_send_event_cb; 513653a5a1b3Sopenharmony_ci c->client->userdata = c; 513753a5a1b3Sopenharmony_ci 513853a5a1b3Sopenharmony_ci c->rw_mempool = NULL; 513953a5a1b3Sopenharmony_ci 514053a5a1b3Sopenharmony_ci c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); 514153a5a1b3Sopenharmony_ci pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c); 514253a5a1b3Sopenharmony_ci pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c); 514353a5a1b3Sopenharmony_ci pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); 514453a5a1b3Sopenharmony_ci pa_pstream_set_drain_callback(c->pstream, pstream_drain_callback, c); 514553a5a1b3Sopenharmony_ci pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c); 514653a5a1b3Sopenharmony_ci pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c); 514753a5a1b3Sopenharmony_ci 514853a5a1b3Sopenharmony_ci c->pdispatch = pa_pdispatch_new(p->core->mainloop, true, command_table, PA_COMMAND_MAX); 514953a5a1b3Sopenharmony_ci 515053a5a1b3Sopenharmony_ci c->record_streams = pa_idxset_new(NULL, NULL); 515153a5a1b3Sopenharmony_ci c->output_streams = pa_idxset_new(NULL, NULL); 515253a5a1b3Sopenharmony_ci 515353a5a1b3Sopenharmony_ci c->rrobin_index = PA_IDXSET_INVALID; 515453a5a1b3Sopenharmony_ci c->subscription = NULL; 515553a5a1b3Sopenharmony_ci 515653a5a1b3Sopenharmony_ci pa_idxset_put(p->connections, c, NULL); 515753a5a1b3Sopenharmony_ci 515853a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 515953a5a1b3Sopenharmony_ci if (pa_iochannel_creds_supported(io)) 516053a5a1b3Sopenharmony_ci pa_iochannel_creds_enable(io); 516153a5a1b3Sopenharmony_ci#endif 516253a5a1b3Sopenharmony_ci 516353a5a1b3Sopenharmony_ci pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_CONNECTION_PUT], c); 516453a5a1b3Sopenharmony_ci} 516553a5a1b3Sopenharmony_ci 516653a5a1b3Sopenharmony_civoid pa_native_protocol_disconnect(pa_native_protocol *p, pa_module *m) { 516753a5a1b3Sopenharmony_ci pa_native_connection *c; 516853a5a1b3Sopenharmony_ci void *state = NULL; 516953a5a1b3Sopenharmony_ci 517053a5a1b3Sopenharmony_ci pa_assert(p); 517153a5a1b3Sopenharmony_ci pa_assert(m); 517253a5a1b3Sopenharmony_ci 517353a5a1b3Sopenharmony_ci while ((c = pa_idxset_iterate(p->connections, &state, NULL))) 517453a5a1b3Sopenharmony_ci if (c->options->module == m) 517553a5a1b3Sopenharmony_ci native_connection_unlink(c); 517653a5a1b3Sopenharmony_ci} 517753a5a1b3Sopenharmony_ci 517853a5a1b3Sopenharmony_cistatic pa_native_protocol* native_protocol_new(pa_core *c) { 517953a5a1b3Sopenharmony_ci pa_native_protocol *p; 518053a5a1b3Sopenharmony_ci pa_native_hook_t h; 518153a5a1b3Sopenharmony_ci 518253a5a1b3Sopenharmony_ci pa_assert(c); 518353a5a1b3Sopenharmony_ci 518453a5a1b3Sopenharmony_ci p = pa_xnew(pa_native_protocol, 1); 518553a5a1b3Sopenharmony_ci PA_REFCNT_INIT(p); 518653a5a1b3Sopenharmony_ci p->core = c; 518753a5a1b3Sopenharmony_ci p->connections = pa_idxset_new(NULL, NULL); 518853a5a1b3Sopenharmony_ci 518953a5a1b3Sopenharmony_ci p->servers = NULL; 519053a5a1b3Sopenharmony_ci 519153a5a1b3Sopenharmony_ci p->extensions = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); 519253a5a1b3Sopenharmony_ci 519353a5a1b3Sopenharmony_ci for (h = 0; h < PA_NATIVE_HOOK_MAX; h++) 519453a5a1b3Sopenharmony_ci pa_hook_init(&p->hooks[h], p); 519553a5a1b3Sopenharmony_ci 519653a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_set(c, "native-protocol", p) >= 0); 519753a5a1b3Sopenharmony_ci 519853a5a1b3Sopenharmony_ci return p; 519953a5a1b3Sopenharmony_ci} 520053a5a1b3Sopenharmony_ci 520153a5a1b3Sopenharmony_cipa_native_protocol* pa_native_protocol_get(pa_core *c) { 520253a5a1b3Sopenharmony_ci pa_native_protocol *p; 520353a5a1b3Sopenharmony_ci 520453a5a1b3Sopenharmony_ci if ((p = pa_shared_get(c, "native-protocol"))) 520553a5a1b3Sopenharmony_ci return pa_native_protocol_ref(p); 520653a5a1b3Sopenharmony_ci 520753a5a1b3Sopenharmony_ci return native_protocol_new(c); 520853a5a1b3Sopenharmony_ci} 520953a5a1b3Sopenharmony_ci 521053a5a1b3Sopenharmony_cipa_native_protocol* pa_native_protocol_ref(pa_native_protocol *p) { 521153a5a1b3Sopenharmony_ci pa_assert(p); 521253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 521353a5a1b3Sopenharmony_ci 521453a5a1b3Sopenharmony_ci PA_REFCNT_INC(p); 521553a5a1b3Sopenharmony_ci 521653a5a1b3Sopenharmony_ci return p; 521753a5a1b3Sopenharmony_ci} 521853a5a1b3Sopenharmony_ci 521953a5a1b3Sopenharmony_civoid pa_native_protocol_unref(pa_native_protocol *p) { 522053a5a1b3Sopenharmony_ci pa_native_connection *c; 522153a5a1b3Sopenharmony_ci pa_native_hook_t h; 522253a5a1b3Sopenharmony_ci 522353a5a1b3Sopenharmony_ci pa_assert(p); 522453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 522553a5a1b3Sopenharmony_ci 522653a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(p) > 0) 522753a5a1b3Sopenharmony_ci return; 522853a5a1b3Sopenharmony_ci 522953a5a1b3Sopenharmony_ci while ((c = pa_idxset_first(p->connections, NULL))) 523053a5a1b3Sopenharmony_ci native_connection_unlink(c); 523153a5a1b3Sopenharmony_ci 523253a5a1b3Sopenharmony_ci pa_idxset_free(p->connections, NULL); 523353a5a1b3Sopenharmony_ci 523453a5a1b3Sopenharmony_ci pa_strlist_free(p->servers); 523553a5a1b3Sopenharmony_ci 523653a5a1b3Sopenharmony_ci for (h = 0; h < PA_NATIVE_HOOK_MAX; h++) 523753a5a1b3Sopenharmony_ci pa_hook_done(&p->hooks[h]); 523853a5a1b3Sopenharmony_ci 523953a5a1b3Sopenharmony_ci pa_hashmap_free(p->extensions); 524053a5a1b3Sopenharmony_ci 524153a5a1b3Sopenharmony_ci pa_assert_se(pa_shared_remove(p->core, "native-protocol") >= 0); 524253a5a1b3Sopenharmony_ci 524353a5a1b3Sopenharmony_ci pa_xfree(p); 524453a5a1b3Sopenharmony_ci} 524553a5a1b3Sopenharmony_ci 524653a5a1b3Sopenharmony_civoid pa_native_protocol_add_server_string(pa_native_protocol *p, const char *name) { 524753a5a1b3Sopenharmony_ci pa_assert(p); 524853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 524953a5a1b3Sopenharmony_ci pa_assert(name); 525053a5a1b3Sopenharmony_ci 525153a5a1b3Sopenharmony_ci p->servers = pa_strlist_prepend(p->servers, name); 525253a5a1b3Sopenharmony_ci 525353a5a1b3Sopenharmony_ci pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers); 525453a5a1b3Sopenharmony_ci} 525553a5a1b3Sopenharmony_ci 525653a5a1b3Sopenharmony_civoid pa_native_protocol_remove_server_string(pa_native_protocol *p, const char *name) { 525753a5a1b3Sopenharmony_ci pa_assert(p); 525853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 525953a5a1b3Sopenharmony_ci pa_assert(name); 526053a5a1b3Sopenharmony_ci 526153a5a1b3Sopenharmony_ci p->servers = pa_strlist_remove(p->servers, name); 526253a5a1b3Sopenharmony_ci 526353a5a1b3Sopenharmony_ci pa_hook_fire(&p->hooks[PA_NATIVE_HOOK_SERVERS_CHANGED], p->servers); 526453a5a1b3Sopenharmony_ci} 526553a5a1b3Sopenharmony_ci 526653a5a1b3Sopenharmony_cipa_hook *pa_native_protocol_hooks(pa_native_protocol *p) { 526753a5a1b3Sopenharmony_ci pa_assert(p); 526853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 526953a5a1b3Sopenharmony_ci 527053a5a1b3Sopenharmony_ci return p->hooks; 527153a5a1b3Sopenharmony_ci} 527253a5a1b3Sopenharmony_ci 527353a5a1b3Sopenharmony_cipa_strlist *pa_native_protocol_servers(pa_native_protocol *p) { 527453a5a1b3Sopenharmony_ci pa_assert(p); 527553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 527653a5a1b3Sopenharmony_ci 527753a5a1b3Sopenharmony_ci return p->servers; 527853a5a1b3Sopenharmony_ci} 527953a5a1b3Sopenharmony_ci 528053a5a1b3Sopenharmony_ciint pa_native_protocol_install_ext(pa_native_protocol *p, pa_module *m, pa_native_protocol_ext_cb_t cb) { 528153a5a1b3Sopenharmony_ci pa_assert(p); 528253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 528353a5a1b3Sopenharmony_ci pa_assert(m); 528453a5a1b3Sopenharmony_ci pa_assert(cb); 528553a5a1b3Sopenharmony_ci pa_assert(!pa_hashmap_get(p->extensions, m)); 528653a5a1b3Sopenharmony_ci 528753a5a1b3Sopenharmony_ci pa_assert_se(pa_hashmap_put(p->extensions, m, cb) == 0); 528853a5a1b3Sopenharmony_ci return 0; 528953a5a1b3Sopenharmony_ci} 529053a5a1b3Sopenharmony_ci 529153a5a1b3Sopenharmony_civoid pa_native_protocol_remove_ext(pa_native_protocol *p, pa_module *m) { 529253a5a1b3Sopenharmony_ci pa_assert(p); 529353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(p) >= 1); 529453a5a1b3Sopenharmony_ci pa_assert(m); 529553a5a1b3Sopenharmony_ci 529653a5a1b3Sopenharmony_ci pa_assert_se(pa_hashmap_remove(p->extensions, m)); 529753a5a1b3Sopenharmony_ci} 529853a5a1b3Sopenharmony_ci 529953a5a1b3Sopenharmony_cipa_native_options* pa_native_options_new(void) { 530053a5a1b3Sopenharmony_ci pa_native_options *o; 530153a5a1b3Sopenharmony_ci 530253a5a1b3Sopenharmony_ci o = pa_xnew0(pa_native_options, 1); 530353a5a1b3Sopenharmony_ci PA_REFCNT_INIT(o); 530453a5a1b3Sopenharmony_ci 530553a5a1b3Sopenharmony_ci return o; 530653a5a1b3Sopenharmony_ci} 530753a5a1b3Sopenharmony_ci 530853a5a1b3Sopenharmony_cipa_native_options* pa_native_options_ref(pa_native_options *o) { 530953a5a1b3Sopenharmony_ci pa_assert(o); 531053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 531153a5a1b3Sopenharmony_ci 531253a5a1b3Sopenharmony_ci PA_REFCNT_INC(o); 531353a5a1b3Sopenharmony_ci 531453a5a1b3Sopenharmony_ci return o; 531553a5a1b3Sopenharmony_ci} 531653a5a1b3Sopenharmony_ci 531753a5a1b3Sopenharmony_civoid pa_native_options_unref(pa_native_options *o) { 531853a5a1b3Sopenharmony_ci pa_assert(o); 531953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 532053a5a1b3Sopenharmony_ci 532153a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(o) > 0) 532253a5a1b3Sopenharmony_ci return; 532353a5a1b3Sopenharmony_ci 532453a5a1b3Sopenharmony_ci pa_xfree(o->auth_group); 532553a5a1b3Sopenharmony_ci 532653a5a1b3Sopenharmony_ci if (o->auth_ip_acl) 532753a5a1b3Sopenharmony_ci pa_ip_acl_free(o->auth_ip_acl); 532853a5a1b3Sopenharmony_ci 532953a5a1b3Sopenharmony_ci if (o->auth_cookie) 533053a5a1b3Sopenharmony_ci pa_auth_cookie_unref(o->auth_cookie); 533153a5a1b3Sopenharmony_ci 533253a5a1b3Sopenharmony_ci pa_xfree(o); 533353a5a1b3Sopenharmony_ci} 533453a5a1b3Sopenharmony_ci 533553a5a1b3Sopenharmony_ciint pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) { 533653a5a1b3Sopenharmony_ci bool enabled; 533753a5a1b3Sopenharmony_ci const char *acl; 533853a5a1b3Sopenharmony_ci 533953a5a1b3Sopenharmony_ci pa_assert(o); 534053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 534153a5a1b3Sopenharmony_ci pa_assert(ma); 534253a5a1b3Sopenharmony_ci 534353a5a1b3Sopenharmony_ci o->srbchannel = true; 534453a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "srbchannel", &o->srbchannel) < 0) { 534553a5a1b3Sopenharmony_ci pa_log_error("srbchannel= expects a boolean argument."); 534653a5a1b3Sopenharmony_ci return -1; 534753a5a1b3Sopenharmony_ci } 534853a5a1b3Sopenharmony_ci 534953a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "auth-anonymous", &o->auth_anonymous) < 0) { 535053a5a1b3Sopenharmony_ci pa_log_error("auth-anonymous= expects a boolean argument."); 535153a5a1b3Sopenharmony_ci return -1; 535253a5a1b3Sopenharmony_ci } 535353a5a1b3Sopenharmony_ci 535453a5a1b3Sopenharmony_ci enabled = true; 535553a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "auth-group-enable", &enabled) < 0) { 535653a5a1b3Sopenharmony_ci pa_log_error("auth-group-enable= expects a boolean argument."); 535753a5a1b3Sopenharmony_ci return -1; 535853a5a1b3Sopenharmony_ci } 535953a5a1b3Sopenharmony_ci 536053a5a1b3Sopenharmony_ci pa_xfree(o->auth_group); 536153a5a1b3Sopenharmony_ci o->auth_group = enabled ? pa_xstrdup(pa_modargs_get_value(ma, "auth-group", pa_in_system_mode() ? PA_ACCESS_GROUP : NULL)) : NULL; 536253a5a1b3Sopenharmony_ci 536353a5a1b3Sopenharmony_ci#ifndef HAVE_CREDS 536453a5a1b3Sopenharmony_ci if (o->auth_group) 536553a5a1b3Sopenharmony_ci pa_log_error("Authentication group configured, but not available on local system. Ignoring."); 536653a5a1b3Sopenharmony_ci#endif 536753a5a1b3Sopenharmony_ci 536853a5a1b3Sopenharmony_ci if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { 536953a5a1b3Sopenharmony_ci pa_ip_acl *ipa; 537053a5a1b3Sopenharmony_ci 537153a5a1b3Sopenharmony_ci if (!(ipa = pa_ip_acl_new(acl))) { 537253a5a1b3Sopenharmony_ci pa_log_error("Failed to parse IP ACL '%s'", acl); 537353a5a1b3Sopenharmony_ci return -1; 537453a5a1b3Sopenharmony_ci } 537553a5a1b3Sopenharmony_ci 537653a5a1b3Sopenharmony_ci if (o->auth_ip_acl) 537753a5a1b3Sopenharmony_ci pa_ip_acl_free(o->auth_ip_acl); 537853a5a1b3Sopenharmony_ci 537953a5a1b3Sopenharmony_ci o->auth_ip_acl = ipa; 538053a5a1b3Sopenharmony_ci } 538153a5a1b3Sopenharmony_ci 538253a5a1b3Sopenharmony_ci enabled = true; 538353a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "auth-cookie-enabled", &enabled) < 0) { 538453a5a1b3Sopenharmony_ci pa_log_error("auth-cookie-enabled= expects a boolean argument."); 538553a5a1b3Sopenharmony_ci return -1; 538653a5a1b3Sopenharmony_ci } 538753a5a1b3Sopenharmony_ci 538853a5a1b3Sopenharmony_ci if (o->auth_cookie) 538953a5a1b3Sopenharmony_ci pa_auth_cookie_unref(o->auth_cookie); 539053a5a1b3Sopenharmony_ci 539153a5a1b3Sopenharmony_ci if (enabled) { 539253a5a1b3Sopenharmony_ci const char *cn; 539353a5a1b3Sopenharmony_ci 539453a5a1b3Sopenharmony_ci /* The new name for this is 'auth-cookie', for compat reasons 539553a5a1b3Sopenharmony_ci * we check the old name too */ 539653a5a1b3Sopenharmony_ci cn = pa_modargs_get_value(ma, "auth-cookie", NULL); 539753a5a1b3Sopenharmony_ci if (!cn) 539853a5a1b3Sopenharmony_ci cn = pa_modargs_get_value(ma, "cookie", NULL); 539953a5a1b3Sopenharmony_ci 540053a5a1b3Sopenharmony_ci if (cn) 540153a5a1b3Sopenharmony_ci o->auth_cookie = pa_auth_cookie_get(c, cn, true, PA_NATIVE_COOKIE_LENGTH); 540253a5a1b3Sopenharmony_ci else { 540353a5a1b3Sopenharmony_ci o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, false, PA_NATIVE_COOKIE_LENGTH); 540453a5a1b3Sopenharmony_ci if (!o->auth_cookie) { 540553a5a1b3Sopenharmony_ci char *fallback_path; 540653a5a1b3Sopenharmony_ci 540753a5a1b3Sopenharmony_ci if (pa_append_to_home_dir(PA_NATIVE_COOKIE_FILE_FALLBACK, &fallback_path) >= 0) { 540853a5a1b3Sopenharmony_ci o->auth_cookie = pa_auth_cookie_get(c, fallback_path, false, PA_NATIVE_COOKIE_LENGTH); 540953a5a1b3Sopenharmony_ci pa_xfree(fallback_path); 541053a5a1b3Sopenharmony_ci } 541153a5a1b3Sopenharmony_ci 541253a5a1b3Sopenharmony_ci if (!o->auth_cookie) 541353a5a1b3Sopenharmony_ci o->auth_cookie = pa_auth_cookie_get(c, PA_NATIVE_COOKIE_FILE, true, PA_NATIVE_COOKIE_LENGTH); 541453a5a1b3Sopenharmony_ci } 541553a5a1b3Sopenharmony_ci } 541653a5a1b3Sopenharmony_ci 541753a5a1b3Sopenharmony_ci if (!o->auth_cookie) 541853a5a1b3Sopenharmony_ci return -1; 541953a5a1b3Sopenharmony_ci 542053a5a1b3Sopenharmony_ci } else 542153a5a1b3Sopenharmony_ci o->auth_cookie = NULL; 542253a5a1b3Sopenharmony_ci 542353a5a1b3Sopenharmony_ci return 0; 542453a5a1b3Sopenharmony_ci} 542553a5a1b3Sopenharmony_ci 542653a5a1b3Sopenharmony_cipa_pstream* pa_native_connection_get_pstream(pa_native_connection *c) { 542753a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 542853a5a1b3Sopenharmony_ci 542953a5a1b3Sopenharmony_ci return c->pstream; 543053a5a1b3Sopenharmony_ci} 543153a5a1b3Sopenharmony_ci 543253a5a1b3Sopenharmony_cipa_client* pa_native_connection_get_client(pa_native_connection *c) { 543353a5a1b3Sopenharmony_ci pa_native_connection_assert_ref(c); 543453a5a1b3Sopenharmony_ci 543553a5a1b3Sopenharmony_ci return c->client; 543653a5a1b3Sopenharmony_ci} 5437