153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#include "restart-module.h" 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <unistd.h> 2853a5a1b3Sopenharmony_ci#include <string.h> 2953a5a1b3Sopenharmony_ci#include <errno.h> 3053a5a1b3Sopenharmony_ci#include <sys/types.h> 3153a5a1b3Sopenharmony_ci#include <stdio.h> 3253a5a1b3Sopenharmony_ci#include <stdlib.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#ifdef HAVE_X11 3553a5a1b3Sopenharmony_ci#include <xcb/xcb.h> 3653a5a1b3Sopenharmony_ci#endif 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#include <pulse/rtclock.h> 3953a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 4053a5a1b3Sopenharmony_ci#include <pulse/util.h> 4153a5a1b3Sopenharmony_ci#include <pulse/version.h> 4253a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_ci#include <pulsecore/module.h> 4553a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 4653a5a1b3Sopenharmony_ci#include <pulsecore/modargs.h> 4753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 4853a5a1b3Sopenharmony_ci#include <pulsecore/core-subscribe.h> 4953a5a1b3Sopenharmony_ci#include <pulsecore/pdispatch.h> 5053a5a1b3Sopenharmony_ci#include <pulsecore/pstream.h> 5153a5a1b3Sopenharmony_ci#include <pulsecore/pstream-util.h> 5253a5a1b3Sopenharmony_ci#include <pulsecore/socket-client.h> 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 5553a5a1b3Sopenharmony_ci#include <pulsecore/time-smoother_2.h> 5653a5a1b3Sopenharmony_ci#else 5753a5a1b3Sopenharmony_ci#include <pulsecore/time-smoother.h> 5853a5a1b3Sopenharmony_ci#endif 5953a5a1b3Sopenharmony_ci 6053a5a1b3Sopenharmony_ci#include <pulsecore/thread.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/thread-mq.h> 6253a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 6353a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 6453a5a1b3Sopenharmony_ci#include <pulsecore/proplist-util.h> 6553a5a1b3Sopenharmony_ci#include <pulsecore/auth-cookie.h> 6653a5a1b3Sopenharmony_ci#include <pulsecore/mcalign.h> 6753a5a1b3Sopenharmony_ci#include <pulsecore/strlist.h> 6853a5a1b3Sopenharmony_ci 6953a5a1b3Sopenharmony_ci#ifdef HAVE_X11 7053a5a1b3Sopenharmony_ci#include <pulsecore/x11prop.h> 7153a5a1b3Sopenharmony_ci#endif 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SINK "PULSE_SINK" 7453a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SOURCE "PULSE_SOURCE" 7553a5a1b3Sopenharmony_ci#define ENV_DEFAULT_SERVER "PULSE_SERVER" 7653a5a1b3Sopenharmony_ci#define ENV_COOKIE_FILE "PULSE_COOKIE" 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 7953a5a1b3Sopenharmony_ciPA_MODULE_DESCRIPTION("Tunnel module for sinks"); 8053a5a1b3Sopenharmony_ciPA_MODULE_USAGE( 8153a5a1b3Sopenharmony_ci "sink_name=<name for the local sink> " 8253a5a1b3Sopenharmony_ci "sink_properties=<properties for the local sink> " 8353a5a1b3Sopenharmony_ci "auto=<determine server/sink/cookie automatically> " 8453a5a1b3Sopenharmony_ci "server=<address> " 8553a5a1b3Sopenharmony_ci "sink=<remote sink name> " 8653a5a1b3Sopenharmony_ci "reconnect_interval_ms=<interval to try reconnects, 0 or omitted if disabled> " 8753a5a1b3Sopenharmony_ci "cookie=<filename> " 8853a5a1b3Sopenharmony_ci "format=<sample format> " 8953a5a1b3Sopenharmony_ci "channels=<number of channels> " 9053a5a1b3Sopenharmony_ci "rate=<sample rate> " 9153a5a1b3Sopenharmony_ci "latency_msec=<fixed latency in ms> " 9253a5a1b3Sopenharmony_ci "channel_map=<channel map>"); 9353a5a1b3Sopenharmony_ci#else 9453a5a1b3Sopenharmony_ciPA_MODULE_DESCRIPTION("Tunnel module for sources"); 9553a5a1b3Sopenharmony_ciPA_MODULE_USAGE( 9653a5a1b3Sopenharmony_ci "source_name=<name for the local source> " 9753a5a1b3Sopenharmony_ci "source_properties=<properties for the local source> " 9853a5a1b3Sopenharmony_ci "auto=<determine server/source/cookie automatically> " 9953a5a1b3Sopenharmony_ci "server=<address> " 10053a5a1b3Sopenharmony_ci "source=<remote source name> " 10153a5a1b3Sopenharmony_ci "reconnect_interval_ms=<interval to try reconnects, 0 or omitted if disabled> " 10253a5a1b3Sopenharmony_ci "cookie=<filename> " 10353a5a1b3Sopenharmony_ci "format=<sample format> " 10453a5a1b3Sopenharmony_ci "channels=<number of channels> " 10553a5a1b3Sopenharmony_ci "rate=<sample rate> " 10653a5a1b3Sopenharmony_ci "latency_msec=<fixed latency in ms> " 10753a5a1b3Sopenharmony_ci "channel_map=<channel map>"); 10853a5a1b3Sopenharmony_ci#endif 10953a5a1b3Sopenharmony_ci 11053a5a1b3Sopenharmony_ciPA_MODULE_AUTHOR("Lennart Poettering"); 11153a5a1b3Sopenharmony_ciPA_MODULE_VERSION(PACKAGE_VERSION); 11253a5a1b3Sopenharmony_ciPA_MODULE_LOAD_ONCE(false); 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_cistatic const char* const valid_modargs[] = { 11553a5a1b3Sopenharmony_ci "auto", 11653a5a1b3Sopenharmony_ci "server", 11753a5a1b3Sopenharmony_ci "cookie", 11853a5a1b3Sopenharmony_ci "format", 11953a5a1b3Sopenharmony_ci "channels", 12053a5a1b3Sopenharmony_ci "rate", 12153a5a1b3Sopenharmony_ci "latency_msec", 12253a5a1b3Sopenharmony_ci "reconnect_interval_ms", 12353a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 12453a5a1b3Sopenharmony_ci "sink_name", 12553a5a1b3Sopenharmony_ci "sink_properties", 12653a5a1b3Sopenharmony_ci "sink", 12753a5a1b3Sopenharmony_ci#else 12853a5a1b3Sopenharmony_ci "source_name", 12953a5a1b3Sopenharmony_ci "source_properties", 13053a5a1b3Sopenharmony_ci "source", 13153a5a1b3Sopenharmony_ci#endif 13253a5a1b3Sopenharmony_ci "channel_map", 13353a5a1b3Sopenharmony_ci NULL, 13453a5a1b3Sopenharmony_ci}; 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci#define DEFAULT_TIMEOUT 5 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci#define LATENCY_INTERVAL (1*PA_USEC_PER_SEC) 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci#define MIN_NETWORK_LATENCY_USEC (8*PA_USEC_PER_MSEC) 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 14353a5a1b3Sopenharmony_ci 14453a5a1b3Sopenharmony_cienum { 14553a5a1b3Sopenharmony_ci SINK_MESSAGE_REQUEST = PA_SINK_MESSAGE_MAX, 14653a5a1b3Sopenharmony_ci SINK_MESSAGE_REMOTE_SUSPEND, 14753a5a1b3Sopenharmony_ci SINK_MESSAGE_UPDATE_LATENCY, 14853a5a1b3Sopenharmony_ci SINK_MESSAGE_GET_LATENCY_SNAPSHOT, 14953a5a1b3Sopenharmony_ci SINK_MESSAGE_POST, 15053a5a1b3Sopenharmony_ci}; 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci#define DEFAULT_LATENCY_MSEC 100 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci#else 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_cienum { 15753a5a1b3Sopenharmony_ci SOURCE_MESSAGE_POST = PA_SOURCE_MESSAGE_MAX, 15853a5a1b3Sopenharmony_ci SOURCE_MESSAGE_REMOTE_SUSPEND, 15953a5a1b3Sopenharmony_ci SOURCE_MESSAGE_UPDATE_LATENCY, 16053a5a1b3Sopenharmony_ci SOURCE_MESSAGE_GET_LATENCY_SNAPSHOT, 16153a5a1b3Sopenharmony_ci}; 16253a5a1b3Sopenharmony_ci 16353a5a1b3Sopenharmony_ci#define DEFAULT_LATENCY_MSEC 25 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_ci#endif 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_cistruct tunnel_msg { 16853a5a1b3Sopenharmony_ci pa_msgobject parent; 16953a5a1b3Sopenharmony_ci}; 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_citypedef struct tunnel_msg tunnel_msg; 17253a5a1b3Sopenharmony_ciPA_DEFINE_PRIVATE_CLASS(tunnel_msg, pa_msgobject); 17353a5a1b3Sopenharmony_ci 17453a5a1b3Sopenharmony_cienum { 17553a5a1b3Sopenharmony_ci TUNNEL_MESSAGE_MAYBE_RESTART, 17653a5a1b3Sopenharmony_ci}; 17753a5a1b3Sopenharmony_ci 17853a5a1b3Sopenharmony_cistatic int do_init(pa_module *m); 17953a5a1b3Sopenharmony_cistatic void do_done(pa_module *m); 18053a5a1b3Sopenharmony_ci 18153a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 18253a5a1b3Sopenharmony_cistatic void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18353a5a1b3Sopenharmony_cistatic void command_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18453a5a1b3Sopenharmony_ci#endif 18553a5a1b3Sopenharmony_cistatic void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18653a5a1b3Sopenharmony_cistatic void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18753a5a1b3Sopenharmony_cistatic void command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18853a5a1b3Sopenharmony_cistatic void command_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 18953a5a1b3Sopenharmony_cistatic void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 19053a5a1b3Sopenharmony_cistatic void command_stream_or_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 19153a5a1b3Sopenharmony_cistatic void command_stream_buffer_attr_changed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 19253a5a1b3Sopenharmony_ci 19353a5a1b3Sopenharmony_cistatic const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { 19453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 19553a5a1b3Sopenharmony_ci [PA_COMMAND_REQUEST] = command_request, 19653a5a1b3Sopenharmony_ci [PA_COMMAND_STARTED] = command_started, 19753a5a1b3Sopenharmony_ci#endif 19853a5a1b3Sopenharmony_ci [PA_COMMAND_SUBSCRIBE_EVENT] = command_subscribe_event, 19953a5a1b3Sopenharmony_ci [PA_COMMAND_OVERFLOW] = command_overflow_or_underflow, 20053a5a1b3Sopenharmony_ci [PA_COMMAND_UNDERFLOW] = command_overflow_or_underflow, 20153a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_KILLED] = command_stream_killed, 20253a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_KILLED] = command_stream_killed, 20353a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = command_suspended, 20453a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_SUSPENDED] = command_suspended, 20553a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_MOVED] = command_moved, 20653a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_MOVED] = command_moved, 20753a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_EVENT] = command_stream_or_client_event, 20853a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_EVENT] = command_stream_or_client_event, 20953a5a1b3Sopenharmony_ci [PA_COMMAND_CLIENT_EVENT] = command_stream_or_client_event, 21053a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = command_stream_buffer_attr_changed, 21153a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = command_stream_buffer_attr_changed, 21253a5a1b3Sopenharmony_ci [PA_COMMAND_UNDERFLOW_OHOS] = command_overflow_or_underflow, 21353a5a1b3Sopenharmony_ci}; 21453a5a1b3Sopenharmony_ci 21553a5a1b3Sopenharmony_cistruct userdata { 21653a5a1b3Sopenharmony_ci pa_core *core; 21753a5a1b3Sopenharmony_ci pa_module *module; 21853a5a1b3Sopenharmony_ci 21953a5a1b3Sopenharmony_ci pa_thread_mq thread_mq; 22053a5a1b3Sopenharmony_ci pa_rtpoll *rtpoll; 22153a5a1b3Sopenharmony_ci pa_thread *thread; 22253a5a1b3Sopenharmony_ci 22353a5a1b3Sopenharmony_ci pa_socket_client *client; 22453a5a1b3Sopenharmony_ci pa_pstream *pstream; 22553a5a1b3Sopenharmony_ci pa_pdispatch *pdispatch; 22653a5a1b3Sopenharmony_ci 22753a5a1b3Sopenharmony_ci char *server_name; 22853a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 22953a5a1b3Sopenharmony_ci char *sink_name; 23053a5a1b3Sopenharmony_ci char *configured_sink_name; 23153a5a1b3Sopenharmony_ci pa_sink *sink; 23253a5a1b3Sopenharmony_ci size_t requested_bytes; 23353a5a1b3Sopenharmony_ci#else 23453a5a1b3Sopenharmony_ci char *source_name; 23553a5a1b3Sopenharmony_ci char *configured_source_name; 23653a5a1b3Sopenharmony_ci pa_source *source; 23753a5a1b3Sopenharmony_ci pa_mcalign *mcalign; 23853a5a1b3Sopenharmony_ci#endif 23953a5a1b3Sopenharmony_ci 24053a5a1b3Sopenharmony_ci pa_auth_cookie *auth_cookie; 24153a5a1b3Sopenharmony_ci 24253a5a1b3Sopenharmony_ci uint32_t version; 24353a5a1b3Sopenharmony_ci uint32_t ctag; 24453a5a1b3Sopenharmony_ci uint32_t device_index; 24553a5a1b3Sopenharmony_ci uint32_t channel; 24653a5a1b3Sopenharmony_ci uint32_t latency; 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci int64_t counter; 24953a5a1b3Sopenharmony_ci uint64_t receive_counter; 25053a5a1b3Sopenharmony_ci uint64_t receive_snapshot; 25153a5a1b3Sopenharmony_ci 25253a5a1b3Sopenharmony_ci bool remote_corked:1; 25353a5a1b3Sopenharmony_ci bool remote_suspended:1; 25453a5a1b3Sopenharmony_ci bool shutting_down:1; 25553a5a1b3Sopenharmony_ci 25653a5a1b3Sopenharmony_ci pa_usec_t transport_usec; /* maintained in the main thread */ 25753a5a1b3Sopenharmony_ci pa_usec_t thread_transport_usec; /* maintained in the IO thread */ 25853a5a1b3Sopenharmony_ci 25953a5a1b3Sopenharmony_ci uint32_t ignore_latency_before; 26053a5a1b3Sopenharmony_ci 26153a5a1b3Sopenharmony_ci pa_time_event *time_event; 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 26453a5a1b3Sopenharmony_ci pa_smoother_2 *smoother; 26553a5a1b3Sopenharmony_ci#else 26653a5a1b3Sopenharmony_ci pa_smoother *smoother; 26753a5a1b3Sopenharmony_ci#endif 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci char *device_description; 27053a5a1b3Sopenharmony_ci char *server_fqdn; 27153a5a1b3Sopenharmony_ci char *user_name; 27253a5a1b3Sopenharmony_ci 27353a5a1b3Sopenharmony_ci uint32_t maxlength; 27453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 27553a5a1b3Sopenharmony_ci uint32_t tlength; 27653a5a1b3Sopenharmony_ci uint32_t minreq; 27753a5a1b3Sopenharmony_ci uint32_t prebuf; 27853a5a1b3Sopenharmony_ci 27953a5a1b3Sopenharmony_ci pa_proplist *sink_proplist; 28053a5a1b3Sopenharmony_ci#else 28153a5a1b3Sopenharmony_ci uint32_t fragsize; 28253a5a1b3Sopenharmony_ci 28353a5a1b3Sopenharmony_ci pa_proplist *source_proplist; 28453a5a1b3Sopenharmony_ci#endif 28553a5a1b3Sopenharmony_ci 28653a5a1b3Sopenharmony_ci pa_sample_spec sample_spec; 28753a5a1b3Sopenharmony_ci pa_channel_map channel_map; 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci tunnel_msg *msg; 29053a5a1b3Sopenharmony_ci 29153a5a1b3Sopenharmony_ci pa_iochannel *io; 29253a5a1b3Sopenharmony_ci 29353a5a1b3Sopenharmony_ci pa_usec_t reconnect_interval_us; 29453a5a1b3Sopenharmony_ci pa_usec_t snapshot_time; 29553a5a1b3Sopenharmony_ci}; 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_cistruct module_restart_data { 29853a5a1b3Sopenharmony_ci struct userdata *userdata; 29953a5a1b3Sopenharmony_ci pa_restart_data *restart_data; 30053a5a1b3Sopenharmony_ci}; 30153a5a1b3Sopenharmony_ci 30253a5a1b3Sopenharmony_cistatic void request_latency(struct userdata *u); 30353a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 30453a5a1b3Sopenharmony_cistatic void create_sink(struct userdata *u); 30553a5a1b3Sopenharmony_cistatic void on_sink_created(struct userdata *u); 30653a5a1b3Sopenharmony_ci#else 30753a5a1b3Sopenharmony_cistatic void create_source(struct userdata *u); 30853a5a1b3Sopenharmony_cistatic void on_source_created(struct userdata *u); 30953a5a1b3Sopenharmony_ci#endif 31053a5a1b3Sopenharmony_ci 31153a5a1b3Sopenharmony_ci/* Do a reinit of the module. Note that u will be freed as a result of this 31253a5a1b3Sopenharmony_ci * call. */ 31353a5a1b3Sopenharmony_cistatic void unload_module(struct module_restart_data *rd) { 31453a5a1b3Sopenharmony_ci struct userdata *u = rd->userdata; 31553a5a1b3Sopenharmony_ci 31653a5a1b3Sopenharmony_ci if (rd->restart_data) { 31753a5a1b3Sopenharmony_ci pa_log_debug("Restart already pending"); 31853a5a1b3Sopenharmony_ci return; 31953a5a1b3Sopenharmony_ci } 32053a5a1b3Sopenharmony_ci 32153a5a1b3Sopenharmony_ci if (u->reconnect_interval_us > 0) { 32253a5a1b3Sopenharmony_ci /* The handle returned here must be freed when do_init() was successful and when the 32353a5a1b3Sopenharmony_ci * module exits. */ 32453a5a1b3Sopenharmony_ci rd->restart_data = pa_restart_module_reinit(u->module, do_init, do_done, u->reconnect_interval_us); 32553a5a1b3Sopenharmony_ci } else 32653a5a1b3Sopenharmony_ci pa_module_unload_request(u->module, true); 32753a5a1b3Sopenharmony_ci} 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci/* Called from main context */ 33053a5a1b3Sopenharmony_cistatic void command_stream_or_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 33153a5a1b3Sopenharmony_ci pa_log_debug("Got stream or client event."); 33253a5a1b3Sopenharmony_ci} 33353a5a1b3Sopenharmony_ci 33453a5a1b3Sopenharmony_ci/* Called from main context */ 33553a5a1b3Sopenharmony_cistatic void command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 33653a5a1b3Sopenharmony_ci struct userdata *u = userdata; 33753a5a1b3Sopenharmony_ci 33853a5a1b3Sopenharmony_ci pa_assert(pd); 33953a5a1b3Sopenharmony_ci pa_assert(t); 34053a5a1b3Sopenharmony_ci pa_assert(u); 34153a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_ci pa_log_warn("Stream killed"); 34453a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 34553a5a1b3Sopenharmony_ci} 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci/* Called from main context */ 34853a5a1b3Sopenharmony_cistatic void command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 34953a5a1b3Sopenharmony_ci struct userdata *u = userdata; 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_ci pa_assert(pd); 35253a5a1b3Sopenharmony_ci pa_assert(t); 35353a5a1b3Sopenharmony_ci pa_assert(u); 35453a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 35553a5a1b3Sopenharmony_ci 35653a5a1b3Sopenharmony_ci pa_log_info("Server signalled buffer overrun/underrun."); 35753a5a1b3Sopenharmony_ci request_latency(u); 35853a5a1b3Sopenharmony_ci} 35953a5a1b3Sopenharmony_ci 36053a5a1b3Sopenharmony_ci/* Called from main context */ 36153a5a1b3Sopenharmony_cistatic void command_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 36253a5a1b3Sopenharmony_ci struct userdata *u = userdata; 36353a5a1b3Sopenharmony_ci uint32_t channel; 36453a5a1b3Sopenharmony_ci bool suspended; 36553a5a1b3Sopenharmony_ci 36653a5a1b3Sopenharmony_ci pa_assert(pd); 36753a5a1b3Sopenharmony_ci pa_assert(t); 36853a5a1b3Sopenharmony_ci pa_assert(u); 36953a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 37053a5a1b3Sopenharmony_ci 37153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 37253a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0 || 37353a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 37453a5a1b3Sopenharmony_ci 37553a5a1b3Sopenharmony_ci pa_log("Invalid packet."); 37653a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 37753a5a1b3Sopenharmony_ci return; 37853a5a1b3Sopenharmony_ci } 37953a5a1b3Sopenharmony_ci 38053a5a1b3Sopenharmony_ci pa_log_debug("Server reports device suspend."); 38153a5a1b3Sopenharmony_ci 38253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 38353a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(suspended), 0, NULL); 38453a5a1b3Sopenharmony_ci#else 38553a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(suspended), 0, NULL); 38653a5a1b3Sopenharmony_ci#endif 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci request_latency(u); 38953a5a1b3Sopenharmony_ci} 39053a5a1b3Sopenharmony_ci 39153a5a1b3Sopenharmony_ci/* Called from main context */ 39253a5a1b3Sopenharmony_cistatic void command_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 39353a5a1b3Sopenharmony_ci struct userdata *u = userdata; 39453a5a1b3Sopenharmony_ci uint32_t channel, di; 39553a5a1b3Sopenharmony_ci const char *dn; 39653a5a1b3Sopenharmony_ci bool suspended; 39753a5a1b3Sopenharmony_ci 39853a5a1b3Sopenharmony_ci pa_assert(pd); 39953a5a1b3Sopenharmony_ci pa_assert(t); 40053a5a1b3Sopenharmony_ci pa_assert(u); 40153a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 40253a5a1b3Sopenharmony_ci 40353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 40453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &di) < 0 || 40553a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &dn) < 0 || 40653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0) { 40753a5a1b3Sopenharmony_ci 40853a5a1b3Sopenharmony_ci pa_log_error("Invalid packet."); 40953a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 41053a5a1b3Sopenharmony_ci return; 41153a5a1b3Sopenharmony_ci } 41253a5a1b3Sopenharmony_ci 41353a5a1b3Sopenharmony_ci pa_log_debug("Server reports a stream move."); 41453a5a1b3Sopenharmony_ci 41553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 41653a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(suspended), 0, NULL); 41753a5a1b3Sopenharmony_ci#else 41853a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_REMOTE_SUSPEND, PA_UINT32_TO_PTR(suspended), 0, NULL); 41953a5a1b3Sopenharmony_ci#endif 42053a5a1b3Sopenharmony_ci 42153a5a1b3Sopenharmony_ci request_latency(u); 42253a5a1b3Sopenharmony_ci} 42353a5a1b3Sopenharmony_ci 42453a5a1b3Sopenharmony_cistatic void command_stream_buffer_attr_changed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 42553a5a1b3Sopenharmony_ci struct userdata *u = userdata; 42653a5a1b3Sopenharmony_ci uint32_t channel, maxlength, tlength = 0, fragsize, prebuf, minreq; 42753a5a1b3Sopenharmony_ci pa_usec_t usec; 42853a5a1b3Sopenharmony_ci 42953a5a1b3Sopenharmony_ci pa_assert(pd); 43053a5a1b3Sopenharmony_ci pa_assert(t); 43153a5a1b3Sopenharmony_ci pa_assert(u); 43253a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 43553a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &maxlength) < 0) { 43653a5a1b3Sopenharmony_ci 43753a5a1b3Sopenharmony_ci pa_log_error("Invalid packet."); 43853a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 43953a5a1b3Sopenharmony_ci return; 44053a5a1b3Sopenharmony_ci } 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ci if (command == PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED) { 44353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &fragsize) < 0 || 44453a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 44553a5a1b3Sopenharmony_ci 44653a5a1b3Sopenharmony_ci pa_log_error("Invalid packet."); 44753a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 44853a5a1b3Sopenharmony_ci return; 44953a5a1b3Sopenharmony_ci } 45053a5a1b3Sopenharmony_ci } else { 45153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &tlength) < 0 || 45253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &prebuf) < 0 || 45353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &minreq) < 0 || 45453a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &usec) < 0) { 45553a5a1b3Sopenharmony_ci 45653a5a1b3Sopenharmony_ci pa_log_error("Invalid packet."); 45753a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 45853a5a1b3Sopenharmony_ci return; 45953a5a1b3Sopenharmony_ci } 46053a5a1b3Sopenharmony_ci } 46153a5a1b3Sopenharmony_ci 46253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 46353a5a1b3Sopenharmony_ci pa_log_debug("Server reports buffer attrs changed. tlength now at %lu, before %lu.", (unsigned long) tlength, (unsigned long) u->tlength); 46453a5a1b3Sopenharmony_ci#endif 46553a5a1b3Sopenharmony_ci 46653a5a1b3Sopenharmony_ci request_latency(u); 46753a5a1b3Sopenharmony_ci} 46853a5a1b3Sopenharmony_ci 46953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 47053a5a1b3Sopenharmony_ci 47153a5a1b3Sopenharmony_ci/* Called from main context */ 47253a5a1b3Sopenharmony_cistatic void command_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 47353a5a1b3Sopenharmony_ci struct userdata *u = userdata; 47453a5a1b3Sopenharmony_ci 47553a5a1b3Sopenharmony_ci pa_assert(pd); 47653a5a1b3Sopenharmony_ci pa_assert(t); 47753a5a1b3Sopenharmony_ci pa_assert(u); 47853a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ci pa_log_debug("Server reports playback started."); 48153a5a1b3Sopenharmony_ci request_latency(u); 48253a5a1b3Sopenharmony_ci} 48353a5a1b3Sopenharmony_ci 48453a5a1b3Sopenharmony_ci#endif 48553a5a1b3Sopenharmony_ci 48653a5a1b3Sopenharmony_ci/* Called from IO thread context */ 48753a5a1b3Sopenharmony_cistatic void check_smoother_status(struct userdata *u, bool past) { 48853a5a1b3Sopenharmony_ci pa_usec_t x; 48953a5a1b3Sopenharmony_ci 49053a5a1b3Sopenharmony_ci pa_assert(u); 49153a5a1b3Sopenharmony_ci 49253a5a1b3Sopenharmony_ci x = pa_rtclock_now(); 49353a5a1b3Sopenharmony_ci 49453a5a1b3Sopenharmony_ci /* Correct by the time the requested issued needs to travel to the 49553a5a1b3Sopenharmony_ci * other side. This is a valid thread-safe access, because the 49653a5a1b3Sopenharmony_ci * main thread is waiting for us */ 49753a5a1b3Sopenharmony_ci 49853a5a1b3Sopenharmony_ci if (past) 49953a5a1b3Sopenharmony_ci x -= u->thread_transport_usec; 50053a5a1b3Sopenharmony_ci else 50153a5a1b3Sopenharmony_ci x += u->thread_transport_usec; 50253a5a1b3Sopenharmony_ci 50353a5a1b3Sopenharmony_ci if (u->remote_suspended || u->remote_corked) 50453a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 50553a5a1b3Sopenharmony_ci pa_smoother_2_pause(u->smoother, x); 50653a5a1b3Sopenharmony_ci else 50753a5a1b3Sopenharmony_ci pa_smoother_2_resume(u->smoother, x); 50853a5a1b3Sopenharmony_ci#else 50953a5a1b3Sopenharmony_ci pa_smoother_pause(u->smoother, x); 51053a5a1b3Sopenharmony_ci else 51153a5a1b3Sopenharmony_ci pa_smoother_resume(u->smoother, x, true); 51253a5a1b3Sopenharmony_ci#endif 51353a5a1b3Sopenharmony_ci} 51453a5a1b3Sopenharmony_ci 51553a5a1b3Sopenharmony_ci/* Called from IO thread context */ 51653a5a1b3Sopenharmony_cistatic void stream_cork_within_thread(struct userdata *u, bool cork) { 51753a5a1b3Sopenharmony_ci pa_assert(u); 51853a5a1b3Sopenharmony_ci 51953a5a1b3Sopenharmony_ci if (u->remote_corked == cork) 52053a5a1b3Sopenharmony_ci return; 52153a5a1b3Sopenharmony_ci 52253a5a1b3Sopenharmony_ci u->remote_corked = cork; 52353a5a1b3Sopenharmony_ci check_smoother_status(u, false); 52453a5a1b3Sopenharmony_ci} 52553a5a1b3Sopenharmony_ci 52653a5a1b3Sopenharmony_ci/* Called from main context */ 52753a5a1b3Sopenharmony_cistatic void stream_cork(struct userdata *u, bool cork) { 52853a5a1b3Sopenharmony_ci pa_tagstruct *t; 52953a5a1b3Sopenharmony_ci pa_assert(u); 53053a5a1b3Sopenharmony_ci 53153a5a1b3Sopenharmony_ci if (!u->pstream) 53253a5a1b3Sopenharmony_ci return; 53353a5a1b3Sopenharmony_ci 53453a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 53553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 53653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_CORK_PLAYBACK_STREAM); 53753a5a1b3Sopenharmony_ci#else 53853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_CORK_RECORD_STREAM); 53953a5a1b3Sopenharmony_ci#endif 54053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->ctag++); 54153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->channel); 54253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, cork); 54353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 54453a5a1b3Sopenharmony_ci 54553a5a1b3Sopenharmony_ci request_latency(u); 54653a5a1b3Sopenharmony_ci} 54753a5a1b3Sopenharmony_ci 54853a5a1b3Sopenharmony_ci/* Called from IO thread context */ 54953a5a1b3Sopenharmony_cistatic void stream_suspend_within_thread(struct userdata *u, bool suspend) { 55053a5a1b3Sopenharmony_ci pa_assert(u); 55153a5a1b3Sopenharmony_ci 55253a5a1b3Sopenharmony_ci if (u->remote_suspended == suspend) 55353a5a1b3Sopenharmony_ci return; 55453a5a1b3Sopenharmony_ci 55553a5a1b3Sopenharmony_ci u->remote_suspended = suspend; 55653a5a1b3Sopenharmony_ci check_smoother_status(u, true); 55753a5a1b3Sopenharmony_ci} 55853a5a1b3Sopenharmony_ci 55953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 56053a5a1b3Sopenharmony_ci 56153a5a1b3Sopenharmony_ci/* Called from IO thread context */ 56253a5a1b3Sopenharmony_cistatic void send_data(struct userdata *u) { 56353a5a1b3Sopenharmony_ci pa_assert(u); 56453a5a1b3Sopenharmony_ci 56553a5a1b3Sopenharmony_ci while (u->requested_bytes > 0) { 56653a5a1b3Sopenharmony_ci pa_memchunk memchunk; 56753a5a1b3Sopenharmony_ci 56853a5a1b3Sopenharmony_ci pa_sink_render(u->sink, u->requested_bytes, &memchunk); 56953a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_POST, NULL, 0, &memchunk, NULL); 57053a5a1b3Sopenharmony_ci pa_memblock_unref(memchunk.memblock); 57153a5a1b3Sopenharmony_ci 57253a5a1b3Sopenharmony_ci u->requested_bytes -= memchunk.length; 57353a5a1b3Sopenharmony_ci 57453a5a1b3Sopenharmony_ci u->counter += (int64_t) memchunk.length; 57553a5a1b3Sopenharmony_ci } 57653a5a1b3Sopenharmony_ci} 57753a5a1b3Sopenharmony_ci 57853a5a1b3Sopenharmony_ci/* This function is called from IO context -- except when it is not. */ 57953a5a1b3Sopenharmony_cistatic int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 58053a5a1b3Sopenharmony_ci struct userdata *u = PA_SINK(o)->userdata; 58153a5a1b3Sopenharmony_ci 58253a5a1b3Sopenharmony_ci switch (code) { 58353a5a1b3Sopenharmony_ci 58453a5a1b3Sopenharmony_ci case PA_SINK_MESSAGE_SET_STATE: { 58553a5a1b3Sopenharmony_ci int r; 58653a5a1b3Sopenharmony_ci 58753a5a1b3Sopenharmony_ci /* First, change the state, because otherwise pa_sink_render() would fail */ 58853a5a1b3Sopenharmony_ci if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0) { 58953a5a1b3Sopenharmony_ci 59053a5a1b3Sopenharmony_ci stream_cork_within_thread(u, u->sink->thread_info.state == PA_SINK_SUSPENDED); 59153a5a1b3Sopenharmony_ci 59253a5a1b3Sopenharmony_ci if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) 59353a5a1b3Sopenharmony_ci send_data(u); 59453a5a1b3Sopenharmony_ci } 59553a5a1b3Sopenharmony_ci 59653a5a1b3Sopenharmony_ci return r; 59753a5a1b3Sopenharmony_ci } 59853a5a1b3Sopenharmony_ci 59953a5a1b3Sopenharmony_ci case PA_SINK_MESSAGE_GET_LATENCY: { 60053a5a1b3Sopenharmony_ci int64_t *usec = data; 60153a5a1b3Sopenharmony_ci 60253a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 60353a5a1b3Sopenharmony_ci *usec = pa_smoother_2_get_delay(u->smoother, pa_rtclock_now(), u->counter); 60453a5a1b3Sopenharmony_ci#else 60553a5a1b3Sopenharmony_ci pa_usec_t yl, yr; 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_ci yl = pa_bytes_to_usec((uint64_t) u->counter, &u->sink->sample_spec); 60853a5a1b3Sopenharmony_ci yr = pa_smoother_get(u->smoother, pa_rtclock_now()); 60953a5a1b3Sopenharmony_ci 61053a5a1b3Sopenharmony_ci *usec = (int64_t)yl - yr; 61153a5a1b3Sopenharmony_ci#endif 61253a5a1b3Sopenharmony_ci return 0; 61353a5a1b3Sopenharmony_ci } 61453a5a1b3Sopenharmony_ci 61553a5a1b3Sopenharmony_ci case SINK_MESSAGE_GET_LATENCY_SNAPSHOT: { 61653a5a1b3Sopenharmony_ci int64_t *send_counter = data; 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_ci *send_counter = u->counter; 61953a5a1b3Sopenharmony_ci return 0; 62053a5a1b3Sopenharmony_ci } 62153a5a1b3Sopenharmony_ci 62253a5a1b3Sopenharmony_ci case SINK_MESSAGE_REQUEST: 62353a5a1b3Sopenharmony_ci 62453a5a1b3Sopenharmony_ci pa_assert(offset > 0); 62553a5a1b3Sopenharmony_ci u->requested_bytes += (size_t) offset; 62653a5a1b3Sopenharmony_ci 62753a5a1b3Sopenharmony_ci if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) 62853a5a1b3Sopenharmony_ci send_data(u); 62953a5a1b3Sopenharmony_ci 63053a5a1b3Sopenharmony_ci return 0; 63153a5a1b3Sopenharmony_ci 63253a5a1b3Sopenharmony_ci case SINK_MESSAGE_REMOTE_SUSPEND: 63353a5a1b3Sopenharmony_ci 63453a5a1b3Sopenharmony_ci stream_suspend_within_thread(u, !!PA_PTR_TO_UINT(data)); 63553a5a1b3Sopenharmony_ci return 0; 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci case SINK_MESSAGE_UPDATE_LATENCY: { 63853a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 63953a5a1b3Sopenharmony_ci int64_t bytes; 64053a5a1b3Sopenharmony_ci 64153a5a1b3Sopenharmony_ci if (offset < 0) 64253a5a1b3Sopenharmony_ci bytes = - pa_usec_to_bytes(- offset, &u->sink->sample_spec); 64353a5a1b3Sopenharmony_ci else 64453a5a1b3Sopenharmony_ci bytes = pa_usec_to_bytes(offset, &u->sink->sample_spec); 64553a5a1b3Sopenharmony_ci 64653a5a1b3Sopenharmony_ci if (u->counter > bytes) 64753a5a1b3Sopenharmony_ci bytes = u->counter - bytes; 64853a5a1b3Sopenharmony_ci else 64953a5a1b3Sopenharmony_ci bytes = 0; 65053a5a1b3Sopenharmony_ci 65153a5a1b3Sopenharmony_ci /* We may use u->snapshot time because the main thread is waiting */ 65253a5a1b3Sopenharmony_ci pa_smoother_2_put(u->smoother, u->snapshot_time, bytes); 65353a5a1b3Sopenharmony_ci#else 65453a5a1b3Sopenharmony_ci pa_usec_t y; 65553a5a1b3Sopenharmony_ci 65653a5a1b3Sopenharmony_ci y = pa_bytes_to_usec((uint64_t) u->counter, &u->sink->sample_spec); 65753a5a1b3Sopenharmony_ci 65853a5a1b3Sopenharmony_ci if (y > (pa_usec_t) offset) 65953a5a1b3Sopenharmony_ci y -= (pa_usec_t) offset; 66053a5a1b3Sopenharmony_ci else 66153a5a1b3Sopenharmony_ci y = 0; 66253a5a1b3Sopenharmony_ci 66353a5a1b3Sopenharmony_ci /* We may use u->snapshot time because the main thread is waiting */ 66453a5a1b3Sopenharmony_ci pa_smoother_put(u->smoother, u->snapshot_time, y); 66553a5a1b3Sopenharmony_ci#endif 66653a5a1b3Sopenharmony_ci 66753a5a1b3Sopenharmony_ci /* We can access this freely here, since the main thread is waiting for us */ 66853a5a1b3Sopenharmony_ci u->thread_transport_usec = u->transport_usec; 66953a5a1b3Sopenharmony_ci 67053a5a1b3Sopenharmony_ci return 0; 67153a5a1b3Sopenharmony_ci } 67253a5a1b3Sopenharmony_ci 67353a5a1b3Sopenharmony_ci case SINK_MESSAGE_POST: 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_ci /* OK, This might be a bit confusing. This message is 67653a5a1b3Sopenharmony_ci * delivered to us from the main context -- NOT from the 67753a5a1b3Sopenharmony_ci * IO thread context where the rest of the messages are 67853a5a1b3Sopenharmony_ci * dispatched. Yeah, ugly, but I am a lazy bastard. */ 67953a5a1b3Sopenharmony_ci 68053a5a1b3Sopenharmony_ci pa_pstream_send_memblock(u->pstream, u->channel, 0, PA_SEEK_RELATIVE, chunk); 68153a5a1b3Sopenharmony_ci 68253a5a1b3Sopenharmony_ci u->receive_counter += chunk->length; 68353a5a1b3Sopenharmony_ci 68453a5a1b3Sopenharmony_ci return 0; 68553a5a1b3Sopenharmony_ci } 68653a5a1b3Sopenharmony_ci 68753a5a1b3Sopenharmony_ci return pa_sink_process_msg(o, code, data, offset, chunk); 68853a5a1b3Sopenharmony_ci} 68953a5a1b3Sopenharmony_ci 69053a5a1b3Sopenharmony_ci/* Called from main context */ 69153a5a1b3Sopenharmony_cistatic int sink_set_state_in_main_thread_cb(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) { 69253a5a1b3Sopenharmony_ci struct userdata *u; 69353a5a1b3Sopenharmony_ci pa_sink_assert_ref(s); 69453a5a1b3Sopenharmony_ci u = s->userdata; 69553a5a1b3Sopenharmony_ci 69653a5a1b3Sopenharmony_ci /* It may be that only the suspend cause is changing, in which 69753a5a1b3Sopenharmony_ci * case there's nothing to do. */ 69853a5a1b3Sopenharmony_ci if (state == s->state) 69953a5a1b3Sopenharmony_ci return 0; 70053a5a1b3Sopenharmony_ci 70153a5a1b3Sopenharmony_ci switch ((pa_sink_state_t) state) { 70253a5a1b3Sopenharmony_ci 70353a5a1b3Sopenharmony_ci case PA_SINK_SUSPENDED: 70453a5a1b3Sopenharmony_ci pa_assert(PA_SINK_IS_OPENED(s->state)); 70553a5a1b3Sopenharmony_ci stream_cork(u, true); 70653a5a1b3Sopenharmony_ci break; 70753a5a1b3Sopenharmony_ci 70853a5a1b3Sopenharmony_ci case PA_SINK_IDLE: 70953a5a1b3Sopenharmony_ci case PA_SINK_RUNNING: 71053a5a1b3Sopenharmony_ci if (s->state == PA_SINK_SUSPENDED) 71153a5a1b3Sopenharmony_ci stream_cork(u, false); 71253a5a1b3Sopenharmony_ci break; 71353a5a1b3Sopenharmony_ci 71453a5a1b3Sopenharmony_ci case PA_SINK_UNLINKED: 71553a5a1b3Sopenharmony_ci case PA_SINK_INIT: 71653a5a1b3Sopenharmony_ci case PA_SINK_INVALID_STATE: 71753a5a1b3Sopenharmony_ci ; 71853a5a1b3Sopenharmony_ci } 71953a5a1b3Sopenharmony_ci 72053a5a1b3Sopenharmony_ci return 0; 72153a5a1b3Sopenharmony_ci} 72253a5a1b3Sopenharmony_ci 72353a5a1b3Sopenharmony_ci#else 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci/* This function is called from IO context -- except when it is not. */ 72653a5a1b3Sopenharmony_cistatic int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 72753a5a1b3Sopenharmony_ci struct userdata *u = PA_SOURCE(o)->userdata; 72853a5a1b3Sopenharmony_ci 72953a5a1b3Sopenharmony_ci switch (code) { 73053a5a1b3Sopenharmony_ci 73153a5a1b3Sopenharmony_ci case PA_SOURCE_MESSAGE_SET_STATE: { 73253a5a1b3Sopenharmony_ci int r; 73353a5a1b3Sopenharmony_ci 73453a5a1b3Sopenharmony_ci if ((r = pa_source_process_msg(o, code, data, offset, chunk)) >= 0) 73553a5a1b3Sopenharmony_ci stream_cork_within_thread(u, u->source->thread_info.state == PA_SOURCE_SUSPENDED); 73653a5a1b3Sopenharmony_ci 73753a5a1b3Sopenharmony_ci return r; 73853a5a1b3Sopenharmony_ci } 73953a5a1b3Sopenharmony_ci 74053a5a1b3Sopenharmony_ci case PA_SOURCE_MESSAGE_GET_LATENCY: { 74153a5a1b3Sopenharmony_ci int64_t *usec = data; 74253a5a1b3Sopenharmony_ci 74353a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 74453a5a1b3Sopenharmony_ci *usec = - pa_smoother_2_get_delay(u->smoother, pa_rtclock_now(), u->counter); 74553a5a1b3Sopenharmony_ci#else 74653a5a1b3Sopenharmony_ci pa_usec_t yr, yl; 74753a5a1b3Sopenharmony_ci 74853a5a1b3Sopenharmony_ci yl = pa_bytes_to_usec((uint64_t) u->counter, &PA_SOURCE(o)->sample_spec); 74953a5a1b3Sopenharmony_ci yr = pa_smoother_get(u->smoother, pa_rtclock_now()); 75053a5a1b3Sopenharmony_ci 75153a5a1b3Sopenharmony_ci *usec = (int64_t)yr - yl; 75253a5a1b3Sopenharmony_ci#endif 75353a5a1b3Sopenharmony_ci return 0; 75453a5a1b3Sopenharmony_ci } 75553a5a1b3Sopenharmony_ci 75653a5a1b3Sopenharmony_ci case SOURCE_MESSAGE_GET_LATENCY_SNAPSHOT: { 75753a5a1b3Sopenharmony_ci int64_t *send_counter = data; 75853a5a1b3Sopenharmony_ci 75953a5a1b3Sopenharmony_ci *send_counter = u->counter; 76053a5a1b3Sopenharmony_ci return 0; 76153a5a1b3Sopenharmony_ci } 76253a5a1b3Sopenharmony_ci 76353a5a1b3Sopenharmony_ci case SOURCE_MESSAGE_POST: { 76453a5a1b3Sopenharmony_ci pa_memchunk c; 76553a5a1b3Sopenharmony_ci 76653a5a1b3Sopenharmony_ci pa_mcalign_push(u->mcalign, chunk); 76753a5a1b3Sopenharmony_ci 76853a5a1b3Sopenharmony_ci while (pa_mcalign_pop(u->mcalign, &c) >= 0) { 76953a5a1b3Sopenharmony_ci 77053a5a1b3Sopenharmony_ci if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) 77153a5a1b3Sopenharmony_ci pa_source_post(u->source, &c); 77253a5a1b3Sopenharmony_ci 77353a5a1b3Sopenharmony_ci pa_memblock_unref(c.memblock); 77453a5a1b3Sopenharmony_ci 77553a5a1b3Sopenharmony_ci u->counter += (int64_t) c.length; 77653a5a1b3Sopenharmony_ci } 77753a5a1b3Sopenharmony_ci 77853a5a1b3Sopenharmony_ci return 0; 77953a5a1b3Sopenharmony_ci } 78053a5a1b3Sopenharmony_ci 78153a5a1b3Sopenharmony_ci case SOURCE_MESSAGE_REMOTE_SUSPEND: 78253a5a1b3Sopenharmony_ci 78353a5a1b3Sopenharmony_ci stream_suspend_within_thread(u, !!PA_PTR_TO_UINT(data)); 78453a5a1b3Sopenharmony_ci return 0; 78553a5a1b3Sopenharmony_ci 78653a5a1b3Sopenharmony_ci case SOURCE_MESSAGE_UPDATE_LATENCY: { 78753a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 78853a5a1b3Sopenharmony_ci int64_t bytes; 78953a5a1b3Sopenharmony_ci 79053a5a1b3Sopenharmony_ci if (offset < 0) 79153a5a1b3Sopenharmony_ci bytes = - pa_usec_to_bytes(- offset, &u->source->sample_spec); 79253a5a1b3Sopenharmony_ci else 79353a5a1b3Sopenharmony_ci bytes = pa_usec_to_bytes(offset, &u->source->sample_spec); 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_ci bytes += u->counter; 79653a5a1b3Sopenharmony_ci 79753a5a1b3Sopenharmony_ci /* We may use u->snapshot time because the main thread is waiting */ 79853a5a1b3Sopenharmony_ci pa_smoother_2_put(u->smoother, u->snapshot_time, bytes); 79953a5a1b3Sopenharmony_ci#else 80053a5a1b3Sopenharmony_ci pa_usec_t y; 80153a5a1b3Sopenharmony_ci 80253a5a1b3Sopenharmony_ci y = pa_bytes_to_usec((uint64_t) u->counter, &u->source->sample_spec); 80353a5a1b3Sopenharmony_ci y += offset; 80453a5a1b3Sopenharmony_ci 80553a5a1b3Sopenharmony_ci /* We may use u->snapshot time because the main thread is waiting */ 80653a5a1b3Sopenharmony_ci pa_smoother_put(u->smoother, u->snapshot_time, y); 80753a5a1b3Sopenharmony_ci#endif 80853a5a1b3Sopenharmony_ci 80953a5a1b3Sopenharmony_ci /* We can access this freely here, since the main thread is waiting for us */ 81053a5a1b3Sopenharmony_ci u->thread_transport_usec = u->transport_usec; 81153a5a1b3Sopenharmony_ci 81253a5a1b3Sopenharmony_ci return 0; 81353a5a1b3Sopenharmony_ci } 81453a5a1b3Sopenharmony_ci } 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci return pa_source_process_msg(o, code, data, offset, chunk); 81753a5a1b3Sopenharmony_ci} 81853a5a1b3Sopenharmony_ci 81953a5a1b3Sopenharmony_ci/* Called from main context */ 82053a5a1b3Sopenharmony_cistatic int source_set_state_in_main_thread_cb(pa_source *s, pa_source_state_t state, pa_suspend_cause_t suspend_cause) { 82153a5a1b3Sopenharmony_ci struct userdata *u; 82253a5a1b3Sopenharmony_ci pa_source_assert_ref(s); 82353a5a1b3Sopenharmony_ci u = s->userdata; 82453a5a1b3Sopenharmony_ci 82553a5a1b3Sopenharmony_ci /* It may be that only the suspend cause is changing, in which 82653a5a1b3Sopenharmony_ci * case there's nothing to do. */ 82753a5a1b3Sopenharmony_ci if (state == s->state) 82853a5a1b3Sopenharmony_ci return 0; 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci switch ((pa_source_state_t) state) { 83153a5a1b3Sopenharmony_ci 83253a5a1b3Sopenharmony_ci case PA_SOURCE_SUSPENDED: 83353a5a1b3Sopenharmony_ci pa_assert(PA_SOURCE_IS_OPENED(s->state)); 83453a5a1b3Sopenharmony_ci stream_cork(u, true); 83553a5a1b3Sopenharmony_ci break; 83653a5a1b3Sopenharmony_ci 83753a5a1b3Sopenharmony_ci case PA_SOURCE_IDLE: 83853a5a1b3Sopenharmony_ci case PA_SOURCE_RUNNING: 83953a5a1b3Sopenharmony_ci if (s->state == PA_SOURCE_SUSPENDED) 84053a5a1b3Sopenharmony_ci stream_cork(u, false); 84153a5a1b3Sopenharmony_ci break; 84253a5a1b3Sopenharmony_ci 84353a5a1b3Sopenharmony_ci case PA_SOURCE_UNLINKED: 84453a5a1b3Sopenharmony_ci case PA_SOURCE_INIT: 84553a5a1b3Sopenharmony_ci case PA_SOURCE_INVALID_STATE: 84653a5a1b3Sopenharmony_ci ; 84753a5a1b3Sopenharmony_ci } 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci return 0; 85053a5a1b3Sopenharmony_ci} 85153a5a1b3Sopenharmony_ci 85253a5a1b3Sopenharmony_ci#endif 85353a5a1b3Sopenharmony_ci 85453a5a1b3Sopenharmony_cistatic void thread_func(void *userdata) { 85553a5a1b3Sopenharmony_ci struct userdata *u = userdata; 85653a5a1b3Sopenharmony_ci 85753a5a1b3Sopenharmony_ci pa_assert(u); 85853a5a1b3Sopenharmony_ci 85953a5a1b3Sopenharmony_ci pa_log_debug("Thread starting up"); 86053a5a1b3Sopenharmony_ci 86153a5a1b3Sopenharmony_ci pa_thread_mq_install(&u->thread_mq); 86253a5a1b3Sopenharmony_ci 86353a5a1b3Sopenharmony_ci for (;;) { 86453a5a1b3Sopenharmony_ci int ret; 86553a5a1b3Sopenharmony_ci 86653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 86753a5a1b3Sopenharmony_ci if (u->sink && PA_UNLIKELY(u->sink->thread_info.rewind_requested)) 86853a5a1b3Sopenharmony_ci pa_sink_process_rewind(u->sink, 0); 86953a5a1b3Sopenharmony_ci#endif 87053a5a1b3Sopenharmony_ci 87153a5a1b3Sopenharmony_ci if ((ret = pa_rtpoll_run(u->rtpoll)) < 0) 87253a5a1b3Sopenharmony_ci goto fail; 87353a5a1b3Sopenharmony_ci 87453a5a1b3Sopenharmony_ci if (ret == 0) 87553a5a1b3Sopenharmony_ci goto finish; 87653a5a1b3Sopenharmony_ci } 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_cifail: 87953a5a1b3Sopenharmony_ci /* If this was no regular exit from the loop we have to continue 88053a5a1b3Sopenharmony_ci * processing messages until we received PA_MESSAGE_SHUTDOWN */ 88153a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->msg), TUNNEL_MESSAGE_MAYBE_RESTART, u, 0, NULL, NULL); 88253a5a1b3Sopenharmony_ci pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN); 88353a5a1b3Sopenharmony_ci 88453a5a1b3Sopenharmony_cifinish: 88553a5a1b3Sopenharmony_ci pa_log_debug("Thread shutting down"); 88653a5a1b3Sopenharmony_ci} 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 88953a5a1b3Sopenharmony_ci/* Called from main context */ 89053a5a1b3Sopenharmony_cistatic void command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 89153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 89253a5a1b3Sopenharmony_ci uint32_t bytes, channel; 89353a5a1b3Sopenharmony_ci 89453a5a1b3Sopenharmony_ci pa_assert(pd); 89553a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_REQUEST); 89653a5a1b3Sopenharmony_ci pa_assert(t); 89753a5a1b3Sopenharmony_ci pa_assert(u); 89853a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 89953a5a1b3Sopenharmony_ci 90053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &channel) < 0 || 90153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &bytes) < 0) { 90253a5a1b3Sopenharmony_ci pa_log("Invalid protocol reply"); 90353a5a1b3Sopenharmony_ci goto fail; 90453a5a1b3Sopenharmony_ci } 90553a5a1b3Sopenharmony_ci 90653a5a1b3Sopenharmony_ci if (channel != u->channel) { 90753a5a1b3Sopenharmony_ci pa_log("Received data for invalid channel"); 90853a5a1b3Sopenharmony_ci goto fail; 90953a5a1b3Sopenharmony_ci } 91053a5a1b3Sopenharmony_ci 91153a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL, NULL); 91253a5a1b3Sopenharmony_ci return; 91353a5a1b3Sopenharmony_ci 91453a5a1b3Sopenharmony_cifail: 91553a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 91653a5a1b3Sopenharmony_ci} 91753a5a1b3Sopenharmony_ci 91853a5a1b3Sopenharmony_ci#endif 91953a5a1b3Sopenharmony_ci 92053a5a1b3Sopenharmony_ci/* Called from main context */ 92153a5a1b3Sopenharmony_cistatic void stream_get_latency_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 92253a5a1b3Sopenharmony_ci struct userdata *u = userdata; 92353a5a1b3Sopenharmony_ci pa_usec_t sink_usec, source_usec; 92453a5a1b3Sopenharmony_ci bool playing; 92553a5a1b3Sopenharmony_ci int64_t write_index, read_index; 92653a5a1b3Sopenharmony_ci struct timeval local, remote, now; 92753a5a1b3Sopenharmony_ci pa_sample_spec *ss; 92853a5a1b3Sopenharmony_ci int64_t delay; 92953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 93053a5a1b3Sopenharmony_ci uint64_t send_counter; 93153a5a1b3Sopenharmony_ci#endif 93253a5a1b3Sopenharmony_ci 93353a5a1b3Sopenharmony_ci pa_assert(pd); 93453a5a1b3Sopenharmony_ci pa_assert(u); 93553a5a1b3Sopenharmony_ci 93653a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 93753a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 93853a5a1b3Sopenharmony_ci pa_log("Failed to get latency."); 93953a5a1b3Sopenharmony_ci else 94053a5a1b3Sopenharmony_ci pa_log("Protocol error."); 94153a5a1b3Sopenharmony_ci goto fail; 94253a5a1b3Sopenharmony_ci } 94353a5a1b3Sopenharmony_ci 94453a5a1b3Sopenharmony_ci if (pa_tagstruct_get_usec(t, &sink_usec) < 0 || 94553a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &source_usec) < 0 || 94653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &playing) < 0 || 94753a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &local) < 0 || 94853a5a1b3Sopenharmony_ci pa_tagstruct_get_timeval(t, &remote) < 0 || 94953a5a1b3Sopenharmony_ci pa_tagstruct_gets64(t, &write_index) < 0 || 95053a5a1b3Sopenharmony_ci pa_tagstruct_gets64(t, &read_index) < 0) { 95153a5a1b3Sopenharmony_ci pa_log("Invalid reply."); 95253a5a1b3Sopenharmony_ci goto fail; 95353a5a1b3Sopenharmony_ci } 95453a5a1b3Sopenharmony_ci 95553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 95653a5a1b3Sopenharmony_ci if (u->version >= 13) { 95753a5a1b3Sopenharmony_ci uint64_t underrun_for = 0, playing_for = 0; 95853a5a1b3Sopenharmony_ci 95953a5a1b3Sopenharmony_ci if (pa_tagstruct_getu64(t, &underrun_for) < 0 || 96053a5a1b3Sopenharmony_ci pa_tagstruct_getu64(t, &playing_for) < 0) { 96153a5a1b3Sopenharmony_ci pa_log("Invalid reply."); 96253a5a1b3Sopenharmony_ci goto fail; 96353a5a1b3Sopenharmony_ci } 96453a5a1b3Sopenharmony_ci } 96553a5a1b3Sopenharmony_ci#endif 96653a5a1b3Sopenharmony_ci 96753a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 96853a5a1b3Sopenharmony_ci pa_log("Invalid reply."); 96953a5a1b3Sopenharmony_ci goto fail; 97053a5a1b3Sopenharmony_ci } 97153a5a1b3Sopenharmony_ci 97253a5a1b3Sopenharmony_ci if (tag < u->ignore_latency_before) { 97353a5a1b3Sopenharmony_ci return; 97453a5a1b3Sopenharmony_ci } 97553a5a1b3Sopenharmony_ci 97653a5a1b3Sopenharmony_ci pa_gettimeofday(&now); 97753a5a1b3Sopenharmony_ci 97853a5a1b3Sopenharmony_ci /* Calculate transport usec */ 97953a5a1b3Sopenharmony_ci if (pa_timeval_cmp(&local, &remote) < 0 && pa_timeval_cmp(&remote, &now) < 0) { 98053a5a1b3Sopenharmony_ci /* local and remote seem to have synchronized clocks */ 98153a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 98253a5a1b3Sopenharmony_ci u->transport_usec = pa_timeval_diff(&remote, &local); 98353a5a1b3Sopenharmony_ci#else 98453a5a1b3Sopenharmony_ci u->transport_usec = pa_timeval_diff(&now, &remote); 98553a5a1b3Sopenharmony_ci#endif 98653a5a1b3Sopenharmony_ci } else 98753a5a1b3Sopenharmony_ci u->transport_usec = pa_timeval_diff(&now, &local)/2; 98853a5a1b3Sopenharmony_ci 98953a5a1b3Sopenharmony_ci /* First, take the device's delay */ 99053a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 99153a5a1b3Sopenharmony_ci delay = (int64_t) sink_usec; 99253a5a1b3Sopenharmony_ci ss = &u->sink->sample_spec; 99353a5a1b3Sopenharmony_ci#else 99453a5a1b3Sopenharmony_ci delay = (int64_t) source_usec; 99553a5a1b3Sopenharmony_ci ss = &u->source->sample_spec; 99653a5a1b3Sopenharmony_ci#endif 99753a5a1b3Sopenharmony_ci 99853a5a1b3Sopenharmony_ci /* Add the length of our server-side buffer */ 99953a5a1b3Sopenharmony_ci if (write_index >= read_index) 100053a5a1b3Sopenharmony_ci delay += (int64_t) pa_bytes_to_usec((uint64_t) (write_index-read_index), ss); 100153a5a1b3Sopenharmony_ci else 100253a5a1b3Sopenharmony_ci delay -= (int64_t) pa_bytes_to_usec((uint64_t) (read_index-write_index), ss); 100353a5a1b3Sopenharmony_ci 100453a5a1b3Sopenharmony_ci /* Our measurements are already out of date, hence correct by the * 100553a5a1b3Sopenharmony_ci * transport latency */ 100653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 100753a5a1b3Sopenharmony_ci delay -= (int64_t) u->transport_usec; 100853a5a1b3Sopenharmony_ci#else 100953a5a1b3Sopenharmony_ci delay += (int64_t) u->transport_usec; 101053a5a1b3Sopenharmony_ci#endif 101153a5a1b3Sopenharmony_ci 101253a5a1b3Sopenharmony_ci /* Now correct by what we have have written since we requested the update. This 101353a5a1b3Sopenharmony_ci * is not necessary for the source, because if data is received between request 101453a5a1b3Sopenharmony_ci * and reply, it was already posted before we requested the source latency. */ 101553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 101653a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_GET_LATENCY_SNAPSHOT, &send_counter, 0, NULL); 101753a5a1b3Sopenharmony_ci delay += (int64_t) pa_bytes_to_usec(send_counter - u->receive_snapshot, ss); 101853a5a1b3Sopenharmony_ci#endif 101953a5a1b3Sopenharmony_ci 102053a5a1b3Sopenharmony_ci /* It may take some time before the async message is executed, so we take a timestamp here */ 102153a5a1b3Sopenharmony_ci u->snapshot_time = pa_rtclock_now(); 102253a5a1b3Sopenharmony_ci 102353a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 102453a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_UPDATE_LATENCY, 0, delay, NULL); 102553a5a1b3Sopenharmony_ci#else 102653a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_UPDATE_LATENCY, 0, delay, NULL); 102753a5a1b3Sopenharmony_ci#endif 102853a5a1b3Sopenharmony_ci 102953a5a1b3Sopenharmony_ci return; 103053a5a1b3Sopenharmony_ci 103153a5a1b3Sopenharmony_cifail: 103253a5a1b3Sopenharmony_ci 103353a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 103453a5a1b3Sopenharmony_ci} 103553a5a1b3Sopenharmony_ci 103653a5a1b3Sopenharmony_ci/* Called from main context */ 103753a5a1b3Sopenharmony_cistatic void request_latency(struct userdata *u) { 103853a5a1b3Sopenharmony_ci pa_tagstruct *t; 103953a5a1b3Sopenharmony_ci struct timeval now; 104053a5a1b3Sopenharmony_ci uint32_t tag; 104153a5a1b3Sopenharmony_ci pa_assert(u); 104253a5a1b3Sopenharmony_ci 104353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 104453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 104553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_PLAYBACK_LATENCY); 104653a5a1b3Sopenharmony_ci#else 104753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_RECORD_LATENCY); 104853a5a1b3Sopenharmony_ci#endif 104953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 105053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->channel); 105153a5a1b3Sopenharmony_ci 105253a5a1b3Sopenharmony_ci pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); 105353a5a1b3Sopenharmony_ci 105453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 105553a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_latency_callback, u, NULL); 105653a5a1b3Sopenharmony_ci 105753a5a1b3Sopenharmony_ci u->ignore_latency_before = tag; 105853a5a1b3Sopenharmony_ci u->receive_snapshot = u->receive_counter; 105953a5a1b3Sopenharmony_ci} 106053a5a1b3Sopenharmony_ci 106153a5a1b3Sopenharmony_ci/* Called from main context */ 106253a5a1b3Sopenharmony_cistatic void timeout_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) { 106353a5a1b3Sopenharmony_ci struct userdata *u = userdata; 106453a5a1b3Sopenharmony_ci 106553a5a1b3Sopenharmony_ci pa_assert(m); 106653a5a1b3Sopenharmony_ci pa_assert(e); 106753a5a1b3Sopenharmony_ci pa_assert(u); 106853a5a1b3Sopenharmony_ci 106953a5a1b3Sopenharmony_ci request_latency(u); 107053a5a1b3Sopenharmony_ci 107153a5a1b3Sopenharmony_ci pa_core_rttime_restart(u->core, e, pa_rtclock_now() + LATENCY_INTERVAL); 107253a5a1b3Sopenharmony_ci} 107353a5a1b3Sopenharmony_ci 107453a5a1b3Sopenharmony_ci/* Called from main context */ 107553a5a1b3Sopenharmony_cistatic void update_description(struct userdata *u) { 107653a5a1b3Sopenharmony_ci char *d; 107753a5a1b3Sopenharmony_ci char un[128], hn[128]; 107853a5a1b3Sopenharmony_ci pa_tagstruct *t; 107953a5a1b3Sopenharmony_ci 108053a5a1b3Sopenharmony_ci pa_assert(u); 108153a5a1b3Sopenharmony_ci 108253a5a1b3Sopenharmony_ci if (!u->server_fqdn || !u->user_name || !u->device_description) 108353a5a1b3Sopenharmony_ci return; 108453a5a1b3Sopenharmony_ci 108553a5a1b3Sopenharmony_ci d = pa_sprintf_malloc("%s on %s@%s", u->device_description, u->user_name, u->server_fqdn); 108653a5a1b3Sopenharmony_ci 108753a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 108853a5a1b3Sopenharmony_ci pa_sink_set_description(u->sink, d); 108953a5a1b3Sopenharmony_ci pa_proplist_sets(u->sink->proplist, "tunnel.remote.user", u->user_name); 109053a5a1b3Sopenharmony_ci pa_proplist_sets(u->sink->proplist, "tunnel.remote.fqdn", u->server_fqdn); 109153a5a1b3Sopenharmony_ci pa_proplist_sets(u->sink->proplist, "tunnel.remote.description", u->device_description); 109253a5a1b3Sopenharmony_ci#else 109353a5a1b3Sopenharmony_ci pa_source_set_description(u->source, d); 109453a5a1b3Sopenharmony_ci pa_proplist_sets(u->source->proplist, "tunnel.remote.user", u->user_name); 109553a5a1b3Sopenharmony_ci pa_proplist_sets(u->source->proplist, "tunnel.remote.fqdn", u->server_fqdn); 109653a5a1b3Sopenharmony_ci pa_proplist_sets(u->source->proplist, "tunnel.remote.description", u->device_description); 109753a5a1b3Sopenharmony_ci#endif 109853a5a1b3Sopenharmony_ci 109953a5a1b3Sopenharmony_ci pa_xfree(d); 110053a5a1b3Sopenharmony_ci 110153a5a1b3Sopenharmony_ci d = pa_sprintf_malloc("%s for %s@%s", u->device_description, 110253a5a1b3Sopenharmony_ci pa_get_user_name(un, sizeof(un)), 110353a5a1b3Sopenharmony_ci pa_get_host_name(hn, sizeof(hn))); 110453a5a1b3Sopenharmony_ci 110553a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 110653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 110753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SET_PLAYBACK_STREAM_NAME); 110853a5a1b3Sopenharmony_ci#else 110953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SET_RECORD_STREAM_NAME); 111053a5a1b3Sopenharmony_ci#endif 111153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->ctag++); 111253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->channel); 111353a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, d); 111453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 111553a5a1b3Sopenharmony_ci 111653a5a1b3Sopenharmony_ci pa_xfree(d); 111753a5a1b3Sopenharmony_ci} 111853a5a1b3Sopenharmony_ci 111953a5a1b3Sopenharmony_ci/* Called from main context */ 112053a5a1b3Sopenharmony_cistatic void server_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 112153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 112253a5a1b3Sopenharmony_ci pa_sample_spec ss; 112353a5a1b3Sopenharmony_ci pa_channel_map cm; 112453a5a1b3Sopenharmony_ci const char *server_name, *server_version, *user_name, *host_name, *default_sink_name, *default_source_name; 112553a5a1b3Sopenharmony_ci uint32_t cookie; 112653a5a1b3Sopenharmony_ci 112753a5a1b3Sopenharmony_ci pa_assert(pd); 112853a5a1b3Sopenharmony_ci pa_assert(u); 112953a5a1b3Sopenharmony_ci 113053a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 113153a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 113253a5a1b3Sopenharmony_ci pa_log("Failed to get info."); 113353a5a1b3Sopenharmony_ci else 113453a5a1b3Sopenharmony_ci pa_log("Protocol error."); 113553a5a1b3Sopenharmony_ci goto fail; 113653a5a1b3Sopenharmony_ci } 113753a5a1b3Sopenharmony_ci 113853a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &server_name) < 0 || 113953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &server_version) < 0 || 114053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &user_name) < 0 || 114153a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &host_name) < 0 || 114253a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &ss) < 0 || 114353a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &default_sink_name) < 0 || 114453a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &default_source_name) < 0 || 114553a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &cookie) < 0 || 114653a5a1b3Sopenharmony_ci (u->version >= 15 && pa_tagstruct_get_channel_map(t, &cm) < 0)) { 114753a5a1b3Sopenharmony_ci 114853a5a1b3Sopenharmony_ci pa_log("Parse failure"); 114953a5a1b3Sopenharmony_ci goto fail; 115053a5a1b3Sopenharmony_ci } 115153a5a1b3Sopenharmony_ci 115253a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 115353a5a1b3Sopenharmony_ci pa_log("Packet too long"); 115453a5a1b3Sopenharmony_ci goto fail; 115553a5a1b3Sopenharmony_ci } 115653a5a1b3Sopenharmony_ci 115753a5a1b3Sopenharmony_ci pa_xfree(u->server_fqdn); 115853a5a1b3Sopenharmony_ci u->server_fqdn = pa_xstrdup(host_name); 115953a5a1b3Sopenharmony_ci 116053a5a1b3Sopenharmony_ci pa_xfree(u->user_name); 116153a5a1b3Sopenharmony_ci u->user_name = pa_xstrdup(user_name); 116253a5a1b3Sopenharmony_ci 116353a5a1b3Sopenharmony_ci update_description(u); 116453a5a1b3Sopenharmony_ci 116553a5a1b3Sopenharmony_ci return; 116653a5a1b3Sopenharmony_ci 116753a5a1b3Sopenharmony_cifail: 116853a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 116953a5a1b3Sopenharmony_ci} 117053a5a1b3Sopenharmony_ci 117153a5a1b3Sopenharmony_cistatic int read_ports(struct userdata *u, pa_tagstruct *t) { 117253a5a1b3Sopenharmony_ci if (u->version >= 16) { 117353a5a1b3Sopenharmony_ci uint32_t n_ports; 117453a5a1b3Sopenharmony_ci const char *s; 117553a5a1b3Sopenharmony_ci 117653a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &n_ports)) { 117753a5a1b3Sopenharmony_ci pa_log("Parse failure"); 117853a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 117953a5a1b3Sopenharmony_ci } 118053a5a1b3Sopenharmony_ci 118153a5a1b3Sopenharmony_ci for (uint32_t j = 0; j < n_ports; j++) { 118253a5a1b3Sopenharmony_ci uint32_t priority; 118353a5a1b3Sopenharmony_ci 118453a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &s) < 0 || /* name */ 118553a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &s) < 0 || /* description */ 118653a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &priority) < 0) { 118753a5a1b3Sopenharmony_ci 118853a5a1b3Sopenharmony_ci pa_log("Parse failure"); 118953a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 119053a5a1b3Sopenharmony_ci } 119153a5a1b3Sopenharmony_ci if (u->version >= 24) { 119253a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &priority) < 0) { /* available */ 119353a5a1b3Sopenharmony_ci pa_log("Parse failure"); 119453a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 119553a5a1b3Sopenharmony_ci } 119653a5a1b3Sopenharmony_ci if (u->version >= 34 && 119753a5a1b3Sopenharmony_ci (pa_tagstruct_gets(t, &s) < 0 || /* availability group */ 119853a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &priority) < 0)) { /* device port type */ 119953a5a1b3Sopenharmony_ci pa_log("Parse failure"); 120053a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 120153a5a1b3Sopenharmony_ci } 120253a5a1b3Sopenharmony_ci } 120353a5a1b3Sopenharmony_ci } 120453a5a1b3Sopenharmony_ci 120553a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &s) < 0) { /* active port */ 120653a5a1b3Sopenharmony_ci pa_log("Parse failure"); 120753a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 120853a5a1b3Sopenharmony_ci } 120953a5a1b3Sopenharmony_ci } 121053a5a1b3Sopenharmony_ci return 0; 121153a5a1b3Sopenharmony_ci} 121253a5a1b3Sopenharmony_ci 121353a5a1b3Sopenharmony_cistatic int read_formats(struct userdata *u, pa_tagstruct *t) { 121453a5a1b3Sopenharmony_ci uint8_t n_formats; 121553a5a1b3Sopenharmony_ci pa_format_info *format; 121653a5a1b3Sopenharmony_ci 121753a5a1b3Sopenharmony_ci if (pa_tagstruct_getu8(t, &n_formats) < 0) { /* no. of formats */ 121853a5a1b3Sopenharmony_ci pa_log("Parse failure"); 121953a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 122053a5a1b3Sopenharmony_ci } 122153a5a1b3Sopenharmony_ci 122253a5a1b3Sopenharmony_ci for (uint8_t j = 0; j < n_formats; j++) { 122353a5a1b3Sopenharmony_ci format = pa_format_info_new(); 122453a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, format)) { /* format info */ 122553a5a1b3Sopenharmony_ci pa_format_info_free(format); 122653a5a1b3Sopenharmony_ci pa_log("Parse failure"); 122753a5a1b3Sopenharmony_ci return -PA_ERR_PROTOCOL; 122853a5a1b3Sopenharmony_ci } 122953a5a1b3Sopenharmony_ci pa_format_info_free(format); 123053a5a1b3Sopenharmony_ci } 123153a5a1b3Sopenharmony_ci return 0; 123253a5a1b3Sopenharmony_ci} 123353a5a1b3Sopenharmony_ci 123453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 123553a5a1b3Sopenharmony_ci 123653a5a1b3Sopenharmony_ci/* Called from main context */ 123753a5a1b3Sopenharmony_cistatic void sink_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 123853a5a1b3Sopenharmony_ci struct userdata *u = userdata; 123953a5a1b3Sopenharmony_ci uint32_t idx, owner_module, monitor_source, flags; 124053a5a1b3Sopenharmony_ci const char *name, *description, *monitor_source_name, *driver; 124153a5a1b3Sopenharmony_ci pa_sample_spec ss; 124253a5a1b3Sopenharmony_ci pa_channel_map cm; 124353a5a1b3Sopenharmony_ci pa_cvolume volume; 124453a5a1b3Sopenharmony_ci bool mute; 124553a5a1b3Sopenharmony_ci pa_usec_t latency; 124653a5a1b3Sopenharmony_ci 124753a5a1b3Sopenharmony_ci pa_assert(pd); 124853a5a1b3Sopenharmony_ci pa_assert(u); 124953a5a1b3Sopenharmony_ci 125053a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 125153a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 125253a5a1b3Sopenharmony_ci pa_log("Failed to get info."); 125353a5a1b3Sopenharmony_ci else 125453a5a1b3Sopenharmony_ci pa_log("Protocol error."); 125553a5a1b3Sopenharmony_ci goto fail; 125653a5a1b3Sopenharmony_ci } 125753a5a1b3Sopenharmony_ci 125853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 125953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 126053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &description) < 0 || 126153a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &ss) < 0 || 126253a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &cm) < 0 || 126353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &owner_module) < 0 || 126453a5a1b3Sopenharmony_ci pa_tagstruct_get_cvolume(t, &volume) < 0 || 126553a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &mute) < 0 || 126653a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &monitor_source) < 0 || 126753a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &monitor_source_name) < 0 || 126853a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &latency) < 0 || 126953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &driver) < 0 || 127053a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &flags) < 0) { 127153a5a1b3Sopenharmony_ci 127253a5a1b3Sopenharmony_ci pa_log("Parse failure"); 127353a5a1b3Sopenharmony_ci goto fail; 127453a5a1b3Sopenharmony_ci } 127553a5a1b3Sopenharmony_ci 127653a5a1b3Sopenharmony_ci if (u->version >= 13) { 127753a5a1b3Sopenharmony_ci pa_usec_t configured_latency; 127853a5a1b3Sopenharmony_ci 127953a5a1b3Sopenharmony_ci if (pa_tagstruct_get_proplist(t, NULL) < 0 || 128053a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &configured_latency) < 0) { 128153a5a1b3Sopenharmony_ci 128253a5a1b3Sopenharmony_ci pa_log("Parse failure"); 128353a5a1b3Sopenharmony_ci goto fail; 128453a5a1b3Sopenharmony_ci } 128553a5a1b3Sopenharmony_ci } 128653a5a1b3Sopenharmony_ci 128753a5a1b3Sopenharmony_ci if (u->version >= 15) { 128853a5a1b3Sopenharmony_ci pa_volume_t base_volume; 128953a5a1b3Sopenharmony_ci uint32_t state, n_volume_steps, card; 129053a5a1b3Sopenharmony_ci 129153a5a1b3Sopenharmony_ci if (pa_tagstruct_get_volume(t, &base_volume) < 0 || 129253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &state) < 0 || 129353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &n_volume_steps) < 0 || 129453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &card) < 0) { 129553a5a1b3Sopenharmony_ci 129653a5a1b3Sopenharmony_ci pa_log("Parse failure"); 129753a5a1b3Sopenharmony_ci goto fail; 129853a5a1b3Sopenharmony_ci } 129953a5a1b3Sopenharmony_ci } 130053a5a1b3Sopenharmony_ci 130153a5a1b3Sopenharmony_ci if (read_ports(u, t) < 0) 130253a5a1b3Sopenharmony_ci goto fail; 130353a5a1b3Sopenharmony_ci 130453a5a1b3Sopenharmony_ci if (u->version >= 21 && read_formats(u, t) < 0) 130553a5a1b3Sopenharmony_ci goto fail; 130653a5a1b3Sopenharmony_ci 130753a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 130853a5a1b3Sopenharmony_ci pa_log("Packet too long"); 130953a5a1b3Sopenharmony_ci goto fail; 131053a5a1b3Sopenharmony_ci } 131153a5a1b3Sopenharmony_ci 131253a5a1b3Sopenharmony_ci if (!u->sink_name || !pa_streq(name, u->sink_name)) 131353a5a1b3Sopenharmony_ci return; 131453a5a1b3Sopenharmony_ci 131553a5a1b3Sopenharmony_ci pa_xfree(u->device_description); 131653a5a1b3Sopenharmony_ci u->device_description = pa_xstrdup(description); 131753a5a1b3Sopenharmony_ci 131853a5a1b3Sopenharmony_ci update_description(u); 131953a5a1b3Sopenharmony_ci 132053a5a1b3Sopenharmony_ci return; 132153a5a1b3Sopenharmony_ci 132253a5a1b3Sopenharmony_cifail: 132353a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 132453a5a1b3Sopenharmony_ci} 132553a5a1b3Sopenharmony_ci 132653a5a1b3Sopenharmony_ci/* Called from main context */ 132753a5a1b3Sopenharmony_cistatic void sink_input_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 132853a5a1b3Sopenharmony_ci struct userdata *u = userdata; 132953a5a1b3Sopenharmony_ci uint32_t idx, owner_module, client, sink; 133053a5a1b3Sopenharmony_ci pa_usec_t buffer_usec, sink_usec; 133153a5a1b3Sopenharmony_ci const char *name, *driver, *resample_method; 133253a5a1b3Sopenharmony_ci bool mute = false; 133353a5a1b3Sopenharmony_ci pa_sample_spec sample_spec; 133453a5a1b3Sopenharmony_ci pa_channel_map channel_map; 133553a5a1b3Sopenharmony_ci pa_cvolume volume; 133653a5a1b3Sopenharmony_ci bool b; 133753a5a1b3Sopenharmony_ci 133853a5a1b3Sopenharmony_ci pa_assert(pd); 133953a5a1b3Sopenharmony_ci pa_assert(u); 134053a5a1b3Sopenharmony_ci 134153a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 134253a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 134353a5a1b3Sopenharmony_ci pa_log("Failed to get info."); 134453a5a1b3Sopenharmony_ci else 134553a5a1b3Sopenharmony_ci pa_log("Protocol error."); 134653a5a1b3Sopenharmony_ci goto fail; 134753a5a1b3Sopenharmony_ci } 134853a5a1b3Sopenharmony_ci 134953a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 135053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 135153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &owner_module) < 0 || 135253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &client) < 0 || 135353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &sink) < 0 || 135453a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &sample_spec) < 0 || 135553a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &channel_map) < 0 || 135653a5a1b3Sopenharmony_ci pa_tagstruct_get_cvolume(t, &volume) < 0 || 135753a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &buffer_usec) < 0 || 135853a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &sink_usec) < 0 || 135953a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &resample_method) < 0 || 136053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &driver) < 0) { 136153a5a1b3Sopenharmony_ci 136253a5a1b3Sopenharmony_ci pa_log("Parse failure"); 136353a5a1b3Sopenharmony_ci goto fail; 136453a5a1b3Sopenharmony_ci } 136553a5a1b3Sopenharmony_ci 136653a5a1b3Sopenharmony_ci if (u->version >= 11) { 136753a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &mute) < 0) { 136853a5a1b3Sopenharmony_ci 136953a5a1b3Sopenharmony_ci pa_log("Parse failure"); 137053a5a1b3Sopenharmony_ci goto fail; 137153a5a1b3Sopenharmony_ci } 137253a5a1b3Sopenharmony_ci } 137353a5a1b3Sopenharmony_ci 137453a5a1b3Sopenharmony_ci if (u->version >= 13) { 137553a5a1b3Sopenharmony_ci if (pa_tagstruct_get_proplist(t, NULL) < 0) { 137653a5a1b3Sopenharmony_ci 137753a5a1b3Sopenharmony_ci pa_log("Parse failure"); 137853a5a1b3Sopenharmony_ci goto fail; 137953a5a1b3Sopenharmony_ci } 138053a5a1b3Sopenharmony_ci } 138153a5a1b3Sopenharmony_ci 138253a5a1b3Sopenharmony_ci if (u->version >= 19) { 138353a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &b) < 0) { 138453a5a1b3Sopenharmony_ci 138553a5a1b3Sopenharmony_ci pa_log("Parse failure"); 138653a5a1b3Sopenharmony_ci goto fail; 138753a5a1b3Sopenharmony_ci } 138853a5a1b3Sopenharmony_ci } 138953a5a1b3Sopenharmony_ci 139053a5a1b3Sopenharmony_ci if (u->version >= 20) { 139153a5a1b3Sopenharmony_ci if (pa_tagstruct_get_boolean(t, &b) < 0 || 139253a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &b) < 0) { 139353a5a1b3Sopenharmony_ci 139453a5a1b3Sopenharmony_ci pa_log("Parse failure"); 139553a5a1b3Sopenharmony_ci goto fail; 139653a5a1b3Sopenharmony_ci } 139753a5a1b3Sopenharmony_ci } 139853a5a1b3Sopenharmony_ci 139953a5a1b3Sopenharmony_ci if (u->version >= 21) { 140053a5a1b3Sopenharmony_ci pa_format_info *format = pa_format_info_new(); 140153a5a1b3Sopenharmony_ci 140253a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, format) < 0) { 140353a5a1b3Sopenharmony_ci pa_format_info_free(format); 140453a5a1b3Sopenharmony_ci pa_log("Parse failure"); 140553a5a1b3Sopenharmony_ci goto fail; 140653a5a1b3Sopenharmony_ci } 140753a5a1b3Sopenharmony_ci pa_format_info_free(format); 140853a5a1b3Sopenharmony_ci } 140953a5a1b3Sopenharmony_ci 141053a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 141153a5a1b3Sopenharmony_ci pa_log("Packet too long"); 141253a5a1b3Sopenharmony_ci goto fail; 141353a5a1b3Sopenharmony_ci } 141453a5a1b3Sopenharmony_ci 141553a5a1b3Sopenharmony_ci if (idx != u->device_index) 141653a5a1b3Sopenharmony_ci return; 141753a5a1b3Sopenharmony_ci 141853a5a1b3Sopenharmony_ci pa_assert(u->sink); 141953a5a1b3Sopenharmony_ci 142053a5a1b3Sopenharmony_ci if ((u->version < 11 || mute == u->sink->muted) && 142153a5a1b3Sopenharmony_ci pa_cvolume_equal(&volume, &u->sink->real_volume)) 142253a5a1b3Sopenharmony_ci return; 142353a5a1b3Sopenharmony_ci 142453a5a1b3Sopenharmony_ci pa_sink_volume_changed(u->sink, &volume); 142553a5a1b3Sopenharmony_ci 142653a5a1b3Sopenharmony_ci if (u->version >= 11) 142753a5a1b3Sopenharmony_ci pa_sink_mute_changed(u->sink, mute); 142853a5a1b3Sopenharmony_ci 142953a5a1b3Sopenharmony_ci return; 143053a5a1b3Sopenharmony_ci 143153a5a1b3Sopenharmony_cifail: 143253a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 143353a5a1b3Sopenharmony_ci} 143453a5a1b3Sopenharmony_ci 143553a5a1b3Sopenharmony_ci#else 143653a5a1b3Sopenharmony_ci 143753a5a1b3Sopenharmony_ci/* Called from main context */ 143853a5a1b3Sopenharmony_cistatic void source_info_cb(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 143953a5a1b3Sopenharmony_ci struct userdata *u = userdata; 144053a5a1b3Sopenharmony_ci uint32_t idx, owner_module, monitor_of_sink, flags; 144153a5a1b3Sopenharmony_ci const char *name, *description, *monitor_of_sink_name, *driver; 144253a5a1b3Sopenharmony_ci pa_sample_spec ss; 144353a5a1b3Sopenharmony_ci pa_channel_map cm; 144453a5a1b3Sopenharmony_ci pa_cvolume volume; 144553a5a1b3Sopenharmony_ci bool mute; 144653a5a1b3Sopenharmony_ci pa_usec_t latency, configured_latency; 144753a5a1b3Sopenharmony_ci 144853a5a1b3Sopenharmony_ci pa_assert(pd); 144953a5a1b3Sopenharmony_ci pa_assert(u); 145053a5a1b3Sopenharmony_ci 145153a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 145253a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 145353a5a1b3Sopenharmony_ci pa_log("Failed to get info."); 145453a5a1b3Sopenharmony_ci else 145553a5a1b3Sopenharmony_ci pa_log("Protocol error."); 145653a5a1b3Sopenharmony_ci goto fail; 145753a5a1b3Sopenharmony_ci } 145853a5a1b3Sopenharmony_ci 145953a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 146053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0 || 146153a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &description) < 0 || 146253a5a1b3Sopenharmony_ci pa_tagstruct_get_sample_spec(t, &ss) < 0 || 146353a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &cm) < 0 || 146453a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &owner_module) < 0 || 146553a5a1b3Sopenharmony_ci pa_tagstruct_get_cvolume(t, &volume) < 0 || 146653a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &mute) < 0 || 146753a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &monitor_of_sink) < 0 || 146853a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &monitor_of_sink_name) < 0 || 146953a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &latency) < 0 || 147053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &driver) < 0 || 147153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &flags) < 0) { 147253a5a1b3Sopenharmony_ci 147353a5a1b3Sopenharmony_ci pa_log("Parse failure"); 147453a5a1b3Sopenharmony_ci goto fail; 147553a5a1b3Sopenharmony_ci } 147653a5a1b3Sopenharmony_ci 147753a5a1b3Sopenharmony_ci if (u->version >= 13) { 147853a5a1b3Sopenharmony_ci if (pa_tagstruct_get_proplist(t, NULL) < 0 || 147953a5a1b3Sopenharmony_ci pa_tagstruct_get_usec(t, &configured_latency) < 0) { 148053a5a1b3Sopenharmony_ci 148153a5a1b3Sopenharmony_ci pa_log("Parse failure"); 148253a5a1b3Sopenharmony_ci goto fail; 148353a5a1b3Sopenharmony_ci } 148453a5a1b3Sopenharmony_ci } 148553a5a1b3Sopenharmony_ci 148653a5a1b3Sopenharmony_ci if (u->version >= 15) { 148753a5a1b3Sopenharmony_ci pa_volume_t base_volume; 148853a5a1b3Sopenharmony_ci uint32_t state, n_volume_steps, card; 148953a5a1b3Sopenharmony_ci 149053a5a1b3Sopenharmony_ci if (pa_tagstruct_get_volume(t, &base_volume) < 0 || 149153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &state) < 0 || 149253a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &n_volume_steps) < 0 || 149353a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &card) < 0) { 149453a5a1b3Sopenharmony_ci 149553a5a1b3Sopenharmony_ci pa_log("Parse failure"); 149653a5a1b3Sopenharmony_ci goto fail; 149753a5a1b3Sopenharmony_ci } 149853a5a1b3Sopenharmony_ci } 149953a5a1b3Sopenharmony_ci 150053a5a1b3Sopenharmony_ci if (read_ports(u, t) < 0) 150153a5a1b3Sopenharmony_ci goto fail; 150253a5a1b3Sopenharmony_ci 150353a5a1b3Sopenharmony_ci if (u->version >= 22 && read_formats(u, t) < 0) 150453a5a1b3Sopenharmony_ci goto fail; 150553a5a1b3Sopenharmony_ci 150653a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) { 150753a5a1b3Sopenharmony_ci pa_log("Packet too long"); 150853a5a1b3Sopenharmony_ci goto fail; 150953a5a1b3Sopenharmony_ci } 151053a5a1b3Sopenharmony_ci 151153a5a1b3Sopenharmony_ci if (!u->source_name || !pa_streq(name, u->source_name)) 151253a5a1b3Sopenharmony_ci return; 151353a5a1b3Sopenharmony_ci 151453a5a1b3Sopenharmony_ci pa_xfree(u->device_description); 151553a5a1b3Sopenharmony_ci u->device_description = pa_xstrdup(description); 151653a5a1b3Sopenharmony_ci 151753a5a1b3Sopenharmony_ci update_description(u); 151853a5a1b3Sopenharmony_ci 151953a5a1b3Sopenharmony_ci return; 152053a5a1b3Sopenharmony_ci 152153a5a1b3Sopenharmony_cifail: 152253a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 152353a5a1b3Sopenharmony_ci} 152453a5a1b3Sopenharmony_ci 152553a5a1b3Sopenharmony_ci#endif 152653a5a1b3Sopenharmony_ci 152753a5a1b3Sopenharmony_ci/* Called from main context */ 152853a5a1b3Sopenharmony_cistatic void request_info(struct userdata *u) { 152953a5a1b3Sopenharmony_ci pa_tagstruct *t; 153053a5a1b3Sopenharmony_ci uint32_t tag; 153153a5a1b3Sopenharmony_ci pa_assert(u); 153253a5a1b3Sopenharmony_ci 153353a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 153453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_SERVER_INFO); 153553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 153653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 153753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, server_info_cb, u, NULL); 153853a5a1b3Sopenharmony_ci 153953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 154053a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 154153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INPUT_INFO); 154253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 154353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->device_index); 154453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 154553a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_input_info_cb, u, NULL); 154653a5a1b3Sopenharmony_ci 154753a5a1b3Sopenharmony_ci if (u->sink_name) { 154853a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 154953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_SINK_INFO); 155053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 155153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_INVALID_INDEX); 155253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, u->sink_name); 155353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 155453a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, sink_info_cb, u, NULL); 155553a5a1b3Sopenharmony_ci } 155653a5a1b3Sopenharmony_ci#else 155753a5a1b3Sopenharmony_ci if (u->source_name) { 155853a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 155953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_GET_SOURCE_INFO); 156053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 156153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_INVALID_INDEX); 156253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, u->source_name); 156353a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 156453a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, source_info_cb, u, NULL); 156553a5a1b3Sopenharmony_ci } 156653a5a1b3Sopenharmony_ci#endif 156753a5a1b3Sopenharmony_ci} 156853a5a1b3Sopenharmony_ci 156953a5a1b3Sopenharmony_ci/* Called from main context */ 157053a5a1b3Sopenharmony_cistatic void command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 157153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 157253a5a1b3Sopenharmony_ci pa_subscription_event_type_t e; 157353a5a1b3Sopenharmony_ci uint32_t idx; 157453a5a1b3Sopenharmony_ci 157553a5a1b3Sopenharmony_ci pa_assert(pd); 157653a5a1b3Sopenharmony_ci pa_assert(t); 157753a5a1b3Sopenharmony_ci pa_assert(u); 157853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_SUBSCRIBE_EVENT); 157953a5a1b3Sopenharmony_ci 158053a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &e) < 0 || 158153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &idx) < 0) { 158253a5a1b3Sopenharmony_ci pa_log("Invalid protocol reply"); 158353a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 158453a5a1b3Sopenharmony_ci return; 158553a5a1b3Sopenharmony_ci } 158653a5a1b3Sopenharmony_ci 158753a5a1b3Sopenharmony_ci if (e != (PA_SUBSCRIPTION_EVENT_SERVER|PA_SUBSCRIPTION_EVENT_CHANGE) && 158853a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 158953a5a1b3Sopenharmony_ci e != (PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE) && 159053a5a1b3Sopenharmony_ci e != (PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE) 159153a5a1b3Sopenharmony_ci#else 159253a5a1b3Sopenharmony_ci e != (PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE) 159353a5a1b3Sopenharmony_ci#endif 159453a5a1b3Sopenharmony_ci ) 159553a5a1b3Sopenharmony_ci return; 159653a5a1b3Sopenharmony_ci 159753a5a1b3Sopenharmony_ci request_info(u); 159853a5a1b3Sopenharmony_ci} 159953a5a1b3Sopenharmony_ci 160053a5a1b3Sopenharmony_ci/* Called from main context */ 160153a5a1b3Sopenharmony_cistatic void start_subscribe(struct userdata *u) { 160253a5a1b3Sopenharmony_ci pa_tagstruct *t; 160353a5a1b3Sopenharmony_ci pa_assert(u); 160453a5a1b3Sopenharmony_ci 160553a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 160653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SUBSCRIBE); 160753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->ctag++); 160853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_SUBSCRIPTION_MASK_SERVER| 160953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 161053a5a1b3Sopenharmony_ci PA_SUBSCRIPTION_MASK_SINK_INPUT|PA_SUBSCRIPTION_MASK_SINK 161153a5a1b3Sopenharmony_ci#else 161253a5a1b3Sopenharmony_ci PA_SUBSCRIPTION_MASK_SOURCE 161353a5a1b3Sopenharmony_ci#endif 161453a5a1b3Sopenharmony_ci ); 161553a5a1b3Sopenharmony_ci 161653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 161753a5a1b3Sopenharmony_ci} 161853a5a1b3Sopenharmony_ci 161953a5a1b3Sopenharmony_ci/* Called from main context */ 162053a5a1b3Sopenharmony_cistatic void create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 162153a5a1b3Sopenharmony_ci struct userdata *u = userdata; 162253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 162353a5a1b3Sopenharmony_ci uint32_t bytes; 162453a5a1b3Sopenharmony_ci#endif 162553a5a1b3Sopenharmony_ci 162653a5a1b3Sopenharmony_ci pa_assert(pd); 162753a5a1b3Sopenharmony_ci pa_assert(u); 162853a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 162953a5a1b3Sopenharmony_ci 163053a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 163153a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 163253a5a1b3Sopenharmony_ci pa_log("Failed to create stream."); 163353a5a1b3Sopenharmony_ci else 163453a5a1b3Sopenharmony_ci pa_log("Protocol error."); 163553a5a1b3Sopenharmony_ci goto fail; 163653a5a1b3Sopenharmony_ci } 163753a5a1b3Sopenharmony_ci 163853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &u->channel) < 0 || 163953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->device_index) < 0 164053a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 164153a5a1b3Sopenharmony_ci || pa_tagstruct_getu32(t, &bytes) < 0 164253a5a1b3Sopenharmony_ci#endif 164353a5a1b3Sopenharmony_ci ) 164453a5a1b3Sopenharmony_ci goto parse_error; 164553a5a1b3Sopenharmony_ci 164653a5a1b3Sopenharmony_ci if (u->version >= 9) { 164753a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 164853a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &u->maxlength) < 0 || 164953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->tlength) < 0 || 165053a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->prebuf) < 0 || 165153a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->minreq) < 0) 165253a5a1b3Sopenharmony_ci goto parse_error; 165353a5a1b3Sopenharmony_ci#else 165453a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &u->maxlength) < 0 || 165553a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->fragsize) < 0) 165653a5a1b3Sopenharmony_ci goto parse_error; 165753a5a1b3Sopenharmony_ci#endif 165853a5a1b3Sopenharmony_ci } 165953a5a1b3Sopenharmony_ci 166053a5a1b3Sopenharmony_ci if (u->version >= 12) { 166153a5a1b3Sopenharmony_ci pa_sample_spec ss; 166253a5a1b3Sopenharmony_ci pa_channel_map cm; 166353a5a1b3Sopenharmony_ci uint32_t device_index; 166453a5a1b3Sopenharmony_ci const char *dn; 166553a5a1b3Sopenharmony_ci bool suspended; 166653a5a1b3Sopenharmony_ci 166753a5a1b3Sopenharmony_ci if (pa_tagstruct_get_sample_spec(t, &ss) < 0 || 166853a5a1b3Sopenharmony_ci pa_tagstruct_get_channel_map(t, &cm) < 0 || 166953a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &device_index) < 0 || 167053a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &dn) < 0 || 167153a5a1b3Sopenharmony_ci pa_tagstruct_get_boolean(t, &suspended) < 0) 167253a5a1b3Sopenharmony_ci goto parse_error; 167353a5a1b3Sopenharmony_ci 167453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 167553a5a1b3Sopenharmony_ci pa_xfree(u->sink_name); 167653a5a1b3Sopenharmony_ci u->sink_name = pa_xstrdup(dn); 167753a5a1b3Sopenharmony_ci#else 167853a5a1b3Sopenharmony_ci pa_xfree(u->source_name); 167953a5a1b3Sopenharmony_ci u->source_name = pa_xstrdup(dn); 168053a5a1b3Sopenharmony_ci#endif 168153a5a1b3Sopenharmony_ci } 168253a5a1b3Sopenharmony_ci 168353a5a1b3Sopenharmony_ci if (u->version >= 13) { 168453a5a1b3Sopenharmony_ci pa_usec_t usec; 168553a5a1b3Sopenharmony_ci 168653a5a1b3Sopenharmony_ci if (pa_tagstruct_get_usec(t, &usec) < 0) 168753a5a1b3Sopenharmony_ci goto parse_error; 168853a5a1b3Sopenharmony_ci 168953a5a1b3Sopenharmony_ci/* #ifdef TUNNEL_SINK */ 169053a5a1b3Sopenharmony_ci/* pa_sink_set_latency_range(u->sink, usec + MIN_NETWORK_LATENCY_USEC, 0); */ 169153a5a1b3Sopenharmony_ci/* #else */ 169253a5a1b3Sopenharmony_ci/* pa_source_set_latency_range(u->source, usec + MIN_NETWORK_LATENCY_USEC, 0); */ 169353a5a1b3Sopenharmony_ci/* #endif */ 169453a5a1b3Sopenharmony_ci } 169553a5a1b3Sopenharmony_ci 169653a5a1b3Sopenharmony_ci if (u->version >= 21) { 169753a5a1b3Sopenharmony_ci pa_format_info *format = pa_format_info_new(); 169853a5a1b3Sopenharmony_ci 169953a5a1b3Sopenharmony_ci if (pa_tagstruct_get_format_info(t, format) < 0) { 170053a5a1b3Sopenharmony_ci pa_format_info_free(format); 170153a5a1b3Sopenharmony_ci goto parse_error; 170253a5a1b3Sopenharmony_ci } 170353a5a1b3Sopenharmony_ci 170453a5a1b3Sopenharmony_ci pa_format_info_free(format); 170553a5a1b3Sopenharmony_ci } 170653a5a1b3Sopenharmony_ci 170753a5a1b3Sopenharmony_ci if (!pa_tagstruct_eof(t)) 170853a5a1b3Sopenharmony_ci goto parse_error; 170953a5a1b3Sopenharmony_ci 171053a5a1b3Sopenharmony_ci start_subscribe(u); 171153a5a1b3Sopenharmony_ci request_info(u); 171253a5a1b3Sopenharmony_ci 171353a5a1b3Sopenharmony_ci pa_assert(!u->time_event); 171453a5a1b3Sopenharmony_ci u->time_event = pa_core_rttime_new(u->core, pa_rtclock_now() + LATENCY_INTERVAL, timeout_callback, u); 171553a5a1b3Sopenharmony_ci 171653a5a1b3Sopenharmony_ci request_latency(u); 171753a5a1b3Sopenharmony_ci 171853a5a1b3Sopenharmony_ci pa_log_debug("Stream created."); 171953a5a1b3Sopenharmony_ci 172053a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 172153a5a1b3Sopenharmony_ci pa_asyncmsgq_post(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_REQUEST, NULL, bytes, NULL, NULL); 172253a5a1b3Sopenharmony_ci#endif 172353a5a1b3Sopenharmony_ci 172453a5a1b3Sopenharmony_ci return; 172553a5a1b3Sopenharmony_ci 172653a5a1b3Sopenharmony_ciparse_error: 172753a5a1b3Sopenharmony_ci pa_log("Invalid reply. (Create stream)"); 172853a5a1b3Sopenharmony_ci 172953a5a1b3Sopenharmony_cifail: 173053a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 173153a5a1b3Sopenharmony_ci 173253a5a1b3Sopenharmony_ci} 173353a5a1b3Sopenharmony_ci 173453a5a1b3Sopenharmony_ci/* Called from main context */ 173553a5a1b3Sopenharmony_cistatic void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 173653a5a1b3Sopenharmony_ci struct userdata *u = userdata; 173753a5a1b3Sopenharmony_ci pa_tagstruct *reply; 173853a5a1b3Sopenharmony_ci char name[256], un[128], hn[128]; 173953a5a1b3Sopenharmony_ci pa_cvolume volume; 174053a5a1b3Sopenharmony_ci 174153a5a1b3Sopenharmony_ci pa_assert(pd); 174253a5a1b3Sopenharmony_ci pa_assert(u); 174353a5a1b3Sopenharmony_ci pa_assert(u->pdispatch == pd); 174453a5a1b3Sopenharmony_ci 174553a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY || 174653a5a1b3Sopenharmony_ci pa_tagstruct_getu32(t, &u->version) < 0 || 174753a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 174853a5a1b3Sopenharmony_ci 174953a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) 175053a5a1b3Sopenharmony_ci pa_log("Failed to authenticate"); 175153a5a1b3Sopenharmony_ci else 175253a5a1b3Sopenharmony_ci pa_log("Protocol error."); 175353a5a1b3Sopenharmony_ci 175453a5a1b3Sopenharmony_ci goto fail; 175553a5a1b3Sopenharmony_ci } 175653a5a1b3Sopenharmony_ci 175753a5a1b3Sopenharmony_ci /* Minimum supported protocol version */ 175853a5a1b3Sopenharmony_ci if (u->version < 8) { 175953a5a1b3Sopenharmony_ci pa_log("Incompatible protocol version"); 176053a5a1b3Sopenharmony_ci goto fail; 176153a5a1b3Sopenharmony_ci } 176253a5a1b3Sopenharmony_ci 176353a5a1b3Sopenharmony_ci /* Starting with protocol version 13 the MSB of the version tag 176453a5a1b3Sopenharmony_ci reflects if shm is enabled for this connection or not. We don't 176553a5a1b3Sopenharmony_ci support SHM here at all, so we just ignore this. */ 176653a5a1b3Sopenharmony_ci 176753a5a1b3Sopenharmony_ci if (u->version >= 13) 176853a5a1b3Sopenharmony_ci u->version &= 0x7FFFFFFFU; 176953a5a1b3Sopenharmony_ci 177053a5a1b3Sopenharmony_ci pa_log_debug("Protocol version: remote %u, local %u", u->version, PA_PROTOCOL_VERSION); 177153a5a1b3Sopenharmony_ci 177253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 177353a5a1b3Sopenharmony_ci pa_proplist_setf(u->sink->proplist, "tunnel.remote_version", "%u", u->version); 177453a5a1b3Sopenharmony_ci pa_sink_update_proplist(u->sink, 0, NULL); 177553a5a1b3Sopenharmony_ci 177653a5a1b3Sopenharmony_ci pa_snprintf(name, sizeof(name), "%s for %s@%s", 177753a5a1b3Sopenharmony_ci u->sink_name, 177853a5a1b3Sopenharmony_ci pa_get_user_name(un, sizeof(un)), 177953a5a1b3Sopenharmony_ci pa_get_host_name(hn, sizeof(hn))); 178053a5a1b3Sopenharmony_ci#else 178153a5a1b3Sopenharmony_ci pa_proplist_setf(u->source->proplist, "tunnel.remote_version", "%u", u->version); 178253a5a1b3Sopenharmony_ci pa_source_update_proplist(u->source, 0, NULL); 178353a5a1b3Sopenharmony_ci 178453a5a1b3Sopenharmony_ci pa_snprintf(name, sizeof(name), "%s for %s@%s", 178553a5a1b3Sopenharmony_ci u->source_name, 178653a5a1b3Sopenharmony_ci pa_get_user_name(un, sizeof(un)), 178753a5a1b3Sopenharmony_ci pa_get_host_name(hn, sizeof(hn))); 178853a5a1b3Sopenharmony_ci#endif 178953a5a1b3Sopenharmony_ci 179053a5a1b3Sopenharmony_ci reply = pa_tagstruct_new(); 179153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_COMMAND_SET_CLIENT_NAME); 179253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->ctag++); 179353a5a1b3Sopenharmony_ci 179453a5a1b3Sopenharmony_ci if (u->version >= 13) { 179553a5a1b3Sopenharmony_ci pa_proplist *pl; 179653a5a1b3Sopenharmony_ci pl = pa_proplist_new(); 179753a5a1b3Sopenharmony_ci pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "org.PulseAudio.PulseAudio"); 179853a5a1b3Sopenharmony_ci pa_proplist_sets(pl, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); 179953a5a1b3Sopenharmony_ci pa_init_proplist(pl); 180053a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(reply, pl); 180153a5a1b3Sopenharmony_ci pa_proplist_free(pl); 180253a5a1b3Sopenharmony_ci } else 180353a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, "PulseAudio"); 180453a5a1b3Sopenharmony_ci 180553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, reply); 180653a5a1b3Sopenharmony_ci /* We ignore the server's reply here */ 180753a5a1b3Sopenharmony_ci 180853a5a1b3Sopenharmony_ci reply = pa_tagstruct_new(); 180953a5a1b3Sopenharmony_ci 181053a5a1b3Sopenharmony_ci if (u->version < 13) 181153a5a1b3Sopenharmony_ci /* Only for older PA versions we need to fill in the maxlength */ 181253a5a1b3Sopenharmony_ci u->maxlength = 4*1024*1024; 181353a5a1b3Sopenharmony_ci 181453a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 181553a5a1b3Sopenharmony_ci u->tlength = (uint32_t) pa_usec_to_bytes(PA_USEC_PER_MSEC * u->latency, &u->sink->sample_spec); 181653a5a1b3Sopenharmony_ci u->minreq = (uint32_t) pa_usec_to_bytes(PA_USEC_PER_MSEC * u->latency / 4, &u->sink->sample_spec); 181753a5a1b3Sopenharmony_ci u->prebuf = u->tlength; 181853a5a1b3Sopenharmony_ci#else 181953a5a1b3Sopenharmony_ci u->fragsize = (uint32_t) pa_usec_to_bytes(PA_USEC_PER_MSEC * u->latency, &u->source->sample_spec); 182053a5a1b3Sopenharmony_ci#endif 182153a5a1b3Sopenharmony_ci 182253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 182353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_PLAYBACK_STREAM); 182453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, tag = u->ctag++); 182553a5a1b3Sopenharmony_ci 182653a5a1b3Sopenharmony_ci if (u->version < 13) 182753a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, name); 182853a5a1b3Sopenharmony_ci 182953a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(reply, &u->sink->sample_spec); 183053a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(reply, &u->sink->channel_map); 183153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_INVALID_INDEX); 183253a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, u->sink_name); 183353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->maxlength); 183453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, !PA_SINK_IS_OPENED(u->sink->state)); 183553a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->tlength); 183653a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->prebuf); 183753a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->minreq); 183853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, 0); 183953a5a1b3Sopenharmony_ci pa_cvolume_reset(&volume, u->sink->sample_spec.channels); 184053a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(reply, &volume); 184153a5a1b3Sopenharmony_ci#else 184253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_COMMAND_CREATE_RECORD_STREAM); 184353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, tag = u->ctag++); 184453a5a1b3Sopenharmony_ci 184553a5a1b3Sopenharmony_ci if (u->version < 13) 184653a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, name); 184753a5a1b3Sopenharmony_ci 184853a5a1b3Sopenharmony_ci pa_tagstruct_put_sample_spec(reply, &u->source->sample_spec); 184953a5a1b3Sopenharmony_ci pa_tagstruct_put_channel_map(reply, &u->source->channel_map); 185053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_INVALID_INDEX); 185153a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, u->source_name); 185253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->maxlength); 185353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, !PA_SOURCE_IS_OPENED(u->source->state)); 185453a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, u->fragsize); 185553a5a1b3Sopenharmony_ci#endif 185653a5a1b3Sopenharmony_ci 185753a5a1b3Sopenharmony_ci if (u->version >= 12) { 185853a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* no_remap */ 185953a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* no_remix */ 186053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* fix_format */ 186153a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* fix_rate */ 186253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* fix_channels */ 186353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, true); /* no_move */ 186453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* variable_rate */ 186553a5a1b3Sopenharmony_ci } 186653a5a1b3Sopenharmony_ci 186753a5a1b3Sopenharmony_ci if (u->version >= 13) { 186853a5a1b3Sopenharmony_ci pa_proplist *pl; 186953a5a1b3Sopenharmony_ci 187053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* start muted/peak detect*/ 187153a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, true); /* adjust_latency */ 187253a5a1b3Sopenharmony_ci 187353a5a1b3Sopenharmony_ci pl = pa_proplist_new(); 187453a5a1b3Sopenharmony_ci pa_proplist_sets(pl, PA_PROP_MEDIA_NAME, name); 187553a5a1b3Sopenharmony_ci pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "abstract"); 187653a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(reply, pl); 187753a5a1b3Sopenharmony_ci pa_proplist_free(pl); 187853a5a1b3Sopenharmony_ci 187953a5a1b3Sopenharmony_ci#ifndef TUNNEL_SINK 188053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(reply, PA_INVALID_INDEX); /* direct on input */ 188153a5a1b3Sopenharmony_ci#endif 188253a5a1b3Sopenharmony_ci } 188353a5a1b3Sopenharmony_ci 188453a5a1b3Sopenharmony_ci if (u->version >= 14) { 188553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 188653a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* volume_set */ 188753a5a1b3Sopenharmony_ci#endif 188853a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, true); /* early rquests */ 188953a5a1b3Sopenharmony_ci } 189053a5a1b3Sopenharmony_ci 189153a5a1b3Sopenharmony_ci if (u->version >= 15) { 189253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 189353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* muted_set */ 189453a5a1b3Sopenharmony_ci#endif 189553a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* don't inhibit auto suspend */ 189653a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* fail on suspend */ 189753a5a1b3Sopenharmony_ci } 189853a5a1b3Sopenharmony_ci 189953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 190053a5a1b3Sopenharmony_ci if (u->version >= 17) 190153a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* relative volume */ 190253a5a1b3Sopenharmony_ci 190353a5a1b3Sopenharmony_ci if (u->version >= 18) 190453a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* passthrough stream */ 190553a5a1b3Sopenharmony_ci#endif 190653a5a1b3Sopenharmony_ci 190753a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 190853a5a1b3Sopenharmony_ci if (u->version >= 21) { 190953a5a1b3Sopenharmony_ci /* We're not using the extended API, so n_formats = 0 and that's that */ 191053a5a1b3Sopenharmony_ci pa_tagstruct_putu8(reply, 0); 191153a5a1b3Sopenharmony_ci } 191253a5a1b3Sopenharmony_ci#else 191353a5a1b3Sopenharmony_ci if (u->version >= 22) { 191453a5a1b3Sopenharmony_ci /* We're not using the extended API, so n_formats = 0 and that's that */ 191553a5a1b3Sopenharmony_ci pa_tagstruct_putu8(reply, 0); 191653a5a1b3Sopenharmony_ci pa_cvolume_reset(&volume, u->source->sample_spec.channels); 191753a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(reply, &volume); 191853a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* muted */ 191953a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* volume_set */ 192053a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* muted_set */ 192153a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* relative volume */ 192253a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(reply, false); /* passthrough stream */ 192353a5a1b3Sopenharmony_ci } 192453a5a1b3Sopenharmony_ci#endif 192553a5a1b3Sopenharmony_ci 192653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, reply); 192753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, create_stream_callback, u, NULL); 192853a5a1b3Sopenharmony_ci 192953a5a1b3Sopenharmony_ci pa_log_debug("Connection authenticated, creating stream ..."); 193053a5a1b3Sopenharmony_ci 193153a5a1b3Sopenharmony_ci return; 193253a5a1b3Sopenharmony_ci 193353a5a1b3Sopenharmony_cifail: 193453a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 193553a5a1b3Sopenharmony_ci} 193653a5a1b3Sopenharmony_ci 193753a5a1b3Sopenharmony_ci/* Called from main context */ 193853a5a1b3Sopenharmony_cistatic void pstream_die_callback(pa_pstream *p, void *userdata) { 193953a5a1b3Sopenharmony_ci struct userdata *u = userdata; 194053a5a1b3Sopenharmony_ci 194153a5a1b3Sopenharmony_ci pa_assert(p); 194253a5a1b3Sopenharmony_ci pa_assert(u); 194353a5a1b3Sopenharmony_ci 194453a5a1b3Sopenharmony_ci pa_log_warn("Stream died."); 194553a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 194653a5a1b3Sopenharmony_ci} 194753a5a1b3Sopenharmony_ci 194853a5a1b3Sopenharmony_ci/* Called from main context */ 194953a5a1b3Sopenharmony_cistatic void pstream_packet_callback(pa_pstream *p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) { 195053a5a1b3Sopenharmony_ci struct userdata *u = userdata; 195153a5a1b3Sopenharmony_ci 195253a5a1b3Sopenharmony_ci pa_assert(p); 195353a5a1b3Sopenharmony_ci pa_assert(packet); 195453a5a1b3Sopenharmony_ci pa_assert(u); 195553a5a1b3Sopenharmony_ci 195653a5a1b3Sopenharmony_ci if (pa_pdispatch_run(u->pdispatch, packet, ancil_data, u) < 0) { 195753a5a1b3Sopenharmony_ci pa_log("Invalid packet"); 195853a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 195953a5a1b3Sopenharmony_ci return; 196053a5a1b3Sopenharmony_ci } 196153a5a1b3Sopenharmony_ci} 196253a5a1b3Sopenharmony_ci 196353a5a1b3Sopenharmony_ci#ifndef TUNNEL_SINK 196453a5a1b3Sopenharmony_ci/* Called from main context */ 196553a5a1b3Sopenharmony_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) { 196653a5a1b3Sopenharmony_ci struct userdata *u = userdata; 196753a5a1b3Sopenharmony_ci 196853a5a1b3Sopenharmony_ci pa_assert(p); 196953a5a1b3Sopenharmony_ci pa_assert(chunk); 197053a5a1b3Sopenharmony_ci pa_assert(u); 197153a5a1b3Sopenharmony_ci 197253a5a1b3Sopenharmony_ci if (channel != u->channel) { 197353a5a1b3Sopenharmony_ci pa_log("Received memory block on bad channel."); 197453a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 197553a5a1b3Sopenharmony_ci return; 197653a5a1b3Sopenharmony_ci } 197753a5a1b3Sopenharmony_ci 197853a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->source->asyncmsgq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_POST, PA_UINT_TO_PTR(seek), offset, chunk); 197953a5a1b3Sopenharmony_ci 198053a5a1b3Sopenharmony_ci u->receive_counter += chunk->length; 198153a5a1b3Sopenharmony_ci} 198253a5a1b3Sopenharmony_ci#endif 198353a5a1b3Sopenharmony_ci 198453a5a1b3Sopenharmony_ci/* Called from main context */ 198553a5a1b3Sopenharmony_cistatic void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) { 198653a5a1b3Sopenharmony_ci struct userdata *u = userdata; 198753a5a1b3Sopenharmony_ci 198853a5a1b3Sopenharmony_ci pa_assert_ctl_context(); 198953a5a1b3Sopenharmony_ci 199053a5a1b3Sopenharmony_ci pa_assert(sc); 199153a5a1b3Sopenharmony_ci pa_assert(u); 199253a5a1b3Sopenharmony_ci pa_assert(u->client == sc); 199353a5a1b3Sopenharmony_ci 199453a5a1b3Sopenharmony_ci pa_socket_client_unref(u->client); 199553a5a1b3Sopenharmony_ci u->client = NULL; 199653a5a1b3Sopenharmony_ci 199753a5a1b3Sopenharmony_ci if (!io) { 199853a5a1b3Sopenharmony_ci pa_log("Connection failed: %s", pa_cstrerror(errno)); 199953a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 200053a5a1b3Sopenharmony_ci return; 200153a5a1b3Sopenharmony_ci } 200253a5a1b3Sopenharmony_ci 200353a5a1b3Sopenharmony_ci u->io = io; 200453a5a1b3Sopenharmony_ci 200553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 200653a5a1b3Sopenharmony_ci create_sink(u); 200753a5a1b3Sopenharmony_ci if (!u->sink) { 200853a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 200953a5a1b3Sopenharmony_ci return; 201053a5a1b3Sopenharmony_ci } 201153a5a1b3Sopenharmony_ci on_sink_created(u); 201253a5a1b3Sopenharmony_ci#else 201353a5a1b3Sopenharmony_ci create_source(u); 201453a5a1b3Sopenharmony_ci if (!u->source) { 201553a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 201653a5a1b3Sopenharmony_ci return; 201753a5a1b3Sopenharmony_ci } 201853a5a1b3Sopenharmony_ci on_source_created(u); 201953a5a1b3Sopenharmony_ci#endif 202053a5a1b3Sopenharmony_ci} 202153a5a1b3Sopenharmony_ci 202253a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 202353a5a1b3Sopenharmony_cistatic void on_sink_created(struct userdata *u) 202453a5a1b3Sopenharmony_ci#else 202553a5a1b3Sopenharmony_cistatic void on_source_created(struct userdata *u) 202653a5a1b3Sopenharmony_ci#endif 202753a5a1b3Sopenharmony_ci{ 202853a5a1b3Sopenharmony_ci pa_tagstruct *t; 202953a5a1b3Sopenharmony_ci uint32_t tag; 203053a5a1b3Sopenharmony_ci 203153a5a1b3Sopenharmony_ci u->pstream = pa_pstream_new(u->core->mainloop, u->io, u->core->mempool); 203253a5a1b3Sopenharmony_ci u->pdispatch = pa_pdispatch_new(u->core->mainloop, true, command_table, PA_COMMAND_MAX); 203353a5a1b3Sopenharmony_ci 203453a5a1b3Sopenharmony_ci pa_pstream_set_die_callback(u->pstream, pstream_die_callback, u); 203553a5a1b3Sopenharmony_ci pa_pstream_set_receive_packet_callback(u->pstream, pstream_packet_callback, u); 203653a5a1b3Sopenharmony_ci#ifndef TUNNEL_SINK 203753a5a1b3Sopenharmony_ci pa_pstream_set_receive_memblock_callback(u->pstream, pstream_memblock_callback, u); 203853a5a1b3Sopenharmony_ci#endif 203953a5a1b3Sopenharmony_ci 204053a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 204153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_AUTH); 204253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, tag = u->ctag++); 204353a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); 204453a5a1b3Sopenharmony_ci 204553a5a1b3Sopenharmony_ci pa_tagstruct_put_arbitrary(t, pa_auth_cookie_read(u->auth_cookie, PA_NATIVE_COOKIE_LENGTH), PA_NATIVE_COOKIE_LENGTH); 204653a5a1b3Sopenharmony_ci 204753a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 204853a5a1b3Sopenharmony_ci{ 204953a5a1b3Sopenharmony_ci pa_creds ucred; 205053a5a1b3Sopenharmony_ci 205153a5a1b3Sopenharmony_ci if (pa_iochannel_creds_supported(u->io)) 205253a5a1b3Sopenharmony_ci pa_iochannel_creds_enable(u->io); 205353a5a1b3Sopenharmony_ci 205453a5a1b3Sopenharmony_ci ucred.uid = getuid(); 205553a5a1b3Sopenharmony_ci ucred.gid = getgid(); 205653a5a1b3Sopenharmony_ci 205753a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct_with_creds(u->pstream, t, &ucred); 205853a5a1b3Sopenharmony_ci} 205953a5a1b3Sopenharmony_ci#else 206053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 206153a5a1b3Sopenharmony_ci#endif 206253a5a1b3Sopenharmony_ci 206353a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(u->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, u, NULL); 206453a5a1b3Sopenharmony_ci 206553a5a1b3Sopenharmony_ci pa_log_debug("Connection established, authenticating ..."); 206653a5a1b3Sopenharmony_ci} 206753a5a1b3Sopenharmony_ci 206853a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 206953a5a1b3Sopenharmony_ci 207053a5a1b3Sopenharmony_ci/* Called from main context */ 207153a5a1b3Sopenharmony_cistatic void sink_set_volume(pa_sink *sink) { 207253a5a1b3Sopenharmony_ci struct userdata *u; 207353a5a1b3Sopenharmony_ci pa_tagstruct *t; 207453a5a1b3Sopenharmony_ci 207553a5a1b3Sopenharmony_ci pa_assert(sink); 207653a5a1b3Sopenharmony_ci u = sink->userdata; 207753a5a1b3Sopenharmony_ci pa_assert(u); 207853a5a1b3Sopenharmony_ci 207953a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 208053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_VOLUME); 208153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->ctag++); 208253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->device_index); 208353a5a1b3Sopenharmony_ci pa_tagstruct_put_cvolume(t, &sink->real_volume); 208453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 208553a5a1b3Sopenharmony_ci} 208653a5a1b3Sopenharmony_ci 208753a5a1b3Sopenharmony_ci/* Called from main context */ 208853a5a1b3Sopenharmony_cistatic void sink_set_mute(pa_sink *sink) { 208953a5a1b3Sopenharmony_ci struct userdata *u; 209053a5a1b3Sopenharmony_ci pa_tagstruct *t; 209153a5a1b3Sopenharmony_ci 209253a5a1b3Sopenharmony_ci pa_assert(sink); 209353a5a1b3Sopenharmony_ci u = sink->userdata; 209453a5a1b3Sopenharmony_ci pa_assert(u); 209553a5a1b3Sopenharmony_ci 209653a5a1b3Sopenharmony_ci if (u->version < 11) 209753a5a1b3Sopenharmony_ci return; 209853a5a1b3Sopenharmony_ci 209953a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 210053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_SET_SINK_INPUT_MUTE); 210153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->ctag++); 210253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, u->device_index); 210353a5a1b3Sopenharmony_ci pa_tagstruct_put_boolean(t, sink->muted); 210453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(u->pstream, t); 210553a5a1b3Sopenharmony_ci} 210653a5a1b3Sopenharmony_ci 210753a5a1b3Sopenharmony_ci#endif 210853a5a1b3Sopenharmony_ci 210953a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 211053a5a1b3Sopenharmony_cistatic void create_sink(struct userdata *u) { 211153a5a1b3Sopenharmony_ci pa_sink_new_data data; 211253a5a1b3Sopenharmony_ci char *data_name = NULL; 211353a5a1b3Sopenharmony_ci 211453a5a1b3Sopenharmony_ci if (!(data_name = pa_xstrdup(u->configured_sink_name))) 211553a5a1b3Sopenharmony_ci data_name = pa_sprintf_malloc("tunnel-sink.%s", u->server_name); 211653a5a1b3Sopenharmony_ci 211753a5a1b3Sopenharmony_ci pa_sink_new_data_init(&data); 211853a5a1b3Sopenharmony_ci data.driver = __FILE__; 211953a5a1b3Sopenharmony_ci data.module = u->module; 212053a5a1b3Sopenharmony_ci data.namereg_fail = false; 212153a5a1b3Sopenharmony_ci pa_sink_new_data_set_name(&data, data_name); 212253a5a1b3Sopenharmony_ci pa_sink_new_data_set_sample_spec(&data, &u->sample_spec); 212353a5a1b3Sopenharmony_ci pa_sink_new_data_set_channel_map(&data, &u->channel_map); 212453a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s%s%s", pa_strempty(u->sink_name), u->sink_name ? " on " : "", u->server_name); 212553a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, "tunnel.remote.server", u->server_name); 212653a5a1b3Sopenharmony_ci if (u->sink_name) 212753a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, "tunnel.remote.sink", u->sink_name); 212853a5a1b3Sopenharmony_ci 212953a5a1b3Sopenharmony_ci pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, u->sink_proplist); 213053a5a1b3Sopenharmony_ci 213153a5a1b3Sopenharmony_ci u->sink = pa_sink_new(u->module->core, &data, PA_SINK_NETWORK|PA_SINK_LATENCY); 213253a5a1b3Sopenharmony_ci 213353a5a1b3Sopenharmony_ci if (!u->sink) { 213453a5a1b3Sopenharmony_ci pa_log("Failed to create sink."); 213553a5a1b3Sopenharmony_ci goto finish; 213653a5a1b3Sopenharmony_ci } 213753a5a1b3Sopenharmony_ci 213853a5a1b3Sopenharmony_ci u->sink->parent.process_msg = sink_process_msg; 213953a5a1b3Sopenharmony_ci u->sink->userdata = u; 214053a5a1b3Sopenharmony_ci u->sink->set_state_in_main_thread = sink_set_state_in_main_thread_cb; 214153a5a1b3Sopenharmony_ci pa_sink_set_set_volume_callback(u->sink, sink_set_volume); 214253a5a1b3Sopenharmony_ci pa_sink_set_set_mute_callback(u->sink, sink_set_mute); 214353a5a1b3Sopenharmony_ci 214453a5a1b3Sopenharmony_ci u->sink->refresh_volume = u->sink->refresh_muted = false; 214553a5a1b3Sopenharmony_ci 214653a5a1b3Sopenharmony_ci/* pa_sink_set_latency_range(u->sink, MIN_NETWORK_LATENCY_USEC, 0); */ 214753a5a1b3Sopenharmony_ci 214853a5a1b3Sopenharmony_ci pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq); 214953a5a1b3Sopenharmony_ci pa_sink_set_rtpoll(u->sink, u->rtpoll); 215053a5a1b3Sopenharmony_ci pa_sink_set_fixed_latency(u->sink, u->latency * PA_USEC_PER_MSEC); 215153a5a1b3Sopenharmony_ci 215253a5a1b3Sopenharmony_ci pa_sink_put(u->sink); 215353a5a1b3Sopenharmony_ci 215453a5a1b3Sopenharmony_cifinish: 215553a5a1b3Sopenharmony_ci pa_sink_new_data_done(&data); 215653a5a1b3Sopenharmony_ci pa_xfree(data_name); 215753a5a1b3Sopenharmony_ci} 215853a5a1b3Sopenharmony_ci#else 215953a5a1b3Sopenharmony_cistatic void create_source(struct userdata *u) { 216053a5a1b3Sopenharmony_ci pa_source_new_data data; 216153a5a1b3Sopenharmony_ci char *data_name = NULL; 216253a5a1b3Sopenharmony_ci 216353a5a1b3Sopenharmony_ci if (!(data_name = pa_xstrdup(u->configured_source_name))) 216453a5a1b3Sopenharmony_ci data_name = pa_sprintf_malloc("tunnel-source.%s", u->server_name); 216553a5a1b3Sopenharmony_ci 216653a5a1b3Sopenharmony_ci pa_source_new_data_init(&data); 216753a5a1b3Sopenharmony_ci data.driver = __FILE__; 216853a5a1b3Sopenharmony_ci data.module = u->module; 216953a5a1b3Sopenharmony_ci data.namereg_fail = false; 217053a5a1b3Sopenharmony_ci pa_source_new_data_set_name(&data, data_name); 217153a5a1b3Sopenharmony_ci pa_source_new_data_set_sample_spec(&data, &u->sample_spec); 217253a5a1b3Sopenharmony_ci pa_source_new_data_set_channel_map(&data, &u->channel_map); 217353a5a1b3Sopenharmony_ci pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "%s%s%s", pa_strempty(u->source_name), u->source_name ? " on " : "", u->server_name); 217453a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, "tunnel.remote.server", u->server_name); 217553a5a1b3Sopenharmony_ci if (u->source_name) 217653a5a1b3Sopenharmony_ci pa_proplist_sets(data.proplist, "tunnel.remote.source", u->source_name); 217753a5a1b3Sopenharmony_ci 217853a5a1b3Sopenharmony_ci pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, u->source_proplist); 217953a5a1b3Sopenharmony_ci 218053a5a1b3Sopenharmony_ci u->source = pa_source_new(u->module->core, &data, PA_SOURCE_NETWORK|PA_SOURCE_LATENCY); 218153a5a1b3Sopenharmony_ci 218253a5a1b3Sopenharmony_ci if (!u->source) { 218353a5a1b3Sopenharmony_ci pa_log("Failed to create source."); 218453a5a1b3Sopenharmony_ci goto finish; 218553a5a1b3Sopenharmony_ci } 218653a5a1b3Sopenharmony_ci 218753a5a1b3Sopenharmony_ci u->source->parent.process_msg = source_process_msg; 218853a5a1b3Sopenharmony_ci u->source->set_state_in_main_thread = source_set_state_in_main_thread_cb; 218953a5a1b3Sopenharmony_ci u->source->userdata = u; 219053a5a1b3Sopenharmony_ci 219153a5a1b3Sopenharmony_ci/* pa_source_set_latency_range(u->source, MIN_NETWORK_LATENCY_USEC, 0); */ 219253a5a1b3Sopenharmony_ci 219353a5a1b3Sopenharmony_ci pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); 219453a5a1b3Sopenharmony_ci pa_source_set_rtpoll(u->source, u->rtpoll); 219553a5a1b3Sopenharmony_ci pa_source_set_fixed_latency(u->source, u->latency * PA_USEC_PER_MSEC); 219653a5a1b3Sopenharmony_ci 219753a5a1b3Sopenharmony_ci u->mcalign = pa_mcalign_new(pa_frame_size(&u->source->sample_spec)); 219853a5a1b3Sopenharmony_ci 219953a5a1b3Sopenharmony_ci pa_source_put(u->source); 220053a5a1b3Sopenharmony_ci 220153a5a1b3Sopenharmony_cifinish: 220253a5a1b3Sopenharmony_ci pa_source_new_data_done(&data); 220353a5a1b3Sopenharmony_ci pa_xfree(data_name); 220453a5a1b3Sopenharmony_ci} 220553a5a1b3Sopenharmony_ci#endif 220653a5a1b3Sopenharmony_ci 220753a5a1b3Sopenharmony_ci/* Runs in PA mainloop context */ 220853a5a1b3Sopenharmony_cistatic int tunnel_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { 220953a5a1b3Sopenharmony_ci struct userdata *u = (struct userdata *) data; 221053a5a1b3Sopenharmony_ci 221153a5a1b3Sopenharmony_ci pa_assert(u); 221253a5a1b3Sopenharmony_ci pa_assert_ctl_context(); 221353a5a1b3Sopenharmony_ci 221453a5a1b3Sopenharmony_ci if (u->shutting_down) 221553a5a1b3Sopenharmony_ci return 0; 221653a5a1b3Sopenharmony_ci 221753a5a1b3Sopenharmony_ci switch (code) { 221853a5a1b3Sopenharmony_ci 221953a5a1b3Sopenharmony_ci case TUNNEL_MESSAGE_MAYBE_RESTART: 222053a5a1b3Sopenharmony_ci unload_module(u->module->userdata); 222153a5a1b3Sopenharmony_ci break; 222253a5a1b3Sopenharmony_ci } 222353a5a1b3Sopenharmony_ci 222453a5a1b3Sopenharmony_ci return 0; 222553a5a1b3Sopenharmony_ci} 222653a5a1b3Sopenharmony_ci 222753a5a1b3Sopenharmony_cistatic int start_connect(struct userdata *u, char *server, bool automatic) { 222853a5a1b3Sopenharmony_ci pa_strlist *server_list = NULL; 222953a5a1b3Sopenharmony_ci int rc = 0; 223053a5a1b3Sopenharmony_ci 223153a5a1b3Sopenharmony_ci if (server) { 223253a5a1b3Sopenharmony_ci if (!(server_list = pa_strlist_parse(server))) { 223353a5a1b3Sopenharmony_ci pa_log("Invalid server specified."); 223453a5a1b3Sopenharmony_ci rc = -1; 223553a5a1b3Sopenharmony_ci goto done; 223653a5a1b3Sopenharmony_ci } 223753a5a1b3Sopenharmony_ci } else { 223853a5a1b3Sopenharmony_ci char *ufn; 223953a5a1b3Sopenharmony_ci 224053a5a1b3Sopenharmony_ci if (!automatic) { 224153a5a1b3Sopenharmony_ci pa_log("No server specified."); 224253a5a1b3Sopenharmony_ci rc = -1; 224353a5a1b3Sopenharmony_ci goto done; 224453a5a1b3Sopenharmony_ci } 224553a5a1b3Sopenharmony_ci 224653a5a1b3Sopenharmony_ci pa_log("No server address found. Attempting default local sockets."); 224753a5a1b3Sopenharmony_ci 224853a5a1b3Sopenharmony_ci /* The system wide instance via PF_LOCAL */ 224953a5a1b3Sopenharmony_ci server_list = pa_strlist_prepend(server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); 225053a5a1b3Sopenharmony_ci 225153a5a1b3Sopenharmony_ci /* The user instance via PF_LOCAL */ 225253a5a1b3Sopenharmony_ci if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { 225353a5a1b3Sopenharmony_ci server_list = pa_strlist_prepend(server_list, ufn); 225453a5a1b3Sopenharmony_ci pa_xfree(ufn); 225553a5a1b3Sopenharmony_ci } 225653a5a1b3Sopenharmony_ci } 225753a5a1b3Sopenharmony_ci 225853a5a1b3Sopenharmony_ci for (;;) { 225953a5a1b3Sopenharmony_ci server_list = pa_strlist_pop(server_list, &u->server_name); 226053a5a1b3Sopenharmony_ci 226153a5a1b3Sopenharmony_ci if (!u->server_name) { 226253a5a1b3Sopenharmony_ci if (server) 226353a5a1b3Sopenharmony_ci pa_log("Failed to connect to server '%s'", server); 226453a5a1b3Sopenharmony_ci else 226553a5a1b3Sopenharmony_ci pa_log("Failed to connect"); 226653a5a1b3Sopenharmony_ci rc = -1; 226753a5a1b3Sopenharmony_ci goto done; 226853a5a1b3Sopenharmony_ci } 226953a5a1b3Sopenharmony_ci 227053a5a1b3Sopenharmony_ci pa_log_debug("Trying to connect to %s...", u->server_name); 227153a5a1b3Sopenharmony_ci 227253a5a1b3Sopenharmony_ci if (!(u->client = pa_socket_client_new_string(u->module->core->mainloop, true, u->server_name, PA_NATIVE_DEFAULT_PORT))) { 227353a5a1b3Sopenharmony_ci pa_xfree(u->server_name); 227453a5a1b3Sopenharmony_ci u->server_name = NULL; 227553a5a1b3Sopenharmony_ci continue; 227653a5a1b3Sopenharmony_ci } 227753a5a1b3Sopenharmony_ci 227853a5a1b3Sopenharmony_ci break; 227953a5a1b3Sopenharmony_ci } 228053a5a1b3Sopenharmony_ci 228153a5a1b3Sopenharmony_ci if (u->client) 228253a5a1b3Sopenharmony_ci pa_socket_client_set_callback(u->client, on_connection, u); 228353a5a1b3Sopenharmony_ci 228453a5a1b3Sopenharmony_cidone: 228553a5a1b3Sopenharmony_ci pa_strlist_free(server_list); 228653a5a1b3Sopenharmony_ci 228753a5a1b3Sopenharmony_ci return rc; 228853a5a1b3Sopenharmony_ci} 228953a5a1b3Sopenharmony_ci 229053a5a1b3Sopenharmony_cistatic int do_init(pa_module *m) { 229153a5a1b3Sopenharmony_ci pa_modargs *ma = NULL; 229253a5a1b3Sopenharmony_ci struct userdata *u = NULL; 229353a5a1b3Sopenharmony_ci struct module_restart_data *rd; 229453a5a1b3Sopenharmony_ci char *server = NULL; 229553a5a1b3Sopenharmony_ci uint32_t latency_msec; 229653a5a1b3Sopenharmony_ci bool automatic; 229753a5a1b3Sopenharmony_ci#ifdef HAVE_X11 229853a5a1b3Sopenharmony_ci xcb_connection_t *xcb = NULL; 229953a5a1b3Sopenharmony_ci#endif 230053a5a1b3Sopenharmony_ci const char *cookie_path; 230153a5a1b3Sopenharmony_ci uint32_t reconnect_interval_ms = 0; 230253a5a1b3Sopenharmony_ci 230353a5a1b3Sopenharmony_ci pa_assert(m); 230453a5a1b3Sopenharmony_ci pa_assert(m->userdata); 230553a5a1b3Sopenharmony_ci 230653a5a1b3Sopenharmony_ci rd = m->userdata; 230753a5a1b3Sopenharmony_ci 230853a5a1b3Sopenharmony_ci if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { 230953a5a1b3Sopenharmony_ci pa_log("Failed to parse module arguments"); 231053a5a1b3Sopenharmony_ci goto fail; 231153a5a1b3Sopenharmony_ci } 231253a5a1b3Sopenharmony_ci 231353a5a1b3Sopenharmony_ci rd->userdata = u = pa_xnew0(struct userdata, 1); 231453a5a1b3Sopenharmony_ci u->core = m->core; 231553a5a1b3Sopenharmony_ci u->module = m; 231653a5a1b3Sopenharmony_ci u->client = NULL; 231753a5a1b3Sopenharmony_ci u->pdispatch = NULL; 231853a5a1b3Sopenharmony_ci u->pstream = NULL; 231953a5a1b3Sopenharmony_ci u->server_name = NULL; 232053a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 232153a5a1b3Sopenharmony_ci u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));; 232253a5a1b3Sopenharmony_ci u->configured_sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink_name", NULL)); 232353a5a1b3Sopenharmony_ci u->sink = NULL; 232453a5a1b3Sopenharmony_ci u->requested_bytes = 0; 232553a5a1b3Sopenharmony_ci#else 232653a5a1b3Sopenharmony_ci u->source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));; 232753a5a1b3Sopenharmony_ci u->configured_source_name = pa_xstrdup(pa_modargs_get_value(ma, "source_name", NULL)); 232853a5a1b3Sopenharmony_ci u->source = NULL; 232953a5a1b3Sopenharmony_ci#endif 233053a5a1b3Sopenharmony_ci#ifndef USE_SMOOTHER_2 233153a5a1b3Sopenharmony_ci u->smoother = pa_smoother_new( 233253a5a1b3Sopenharmony_ci PA_USEC_PER_SEC, 233353a5a1b3Sopenharmony_ci PA_USEC_PER_SEC*2, 233453a5a1b3Sopenharmony_ci true, 233553a5a1b3Sopenharmony_ci true, 233653a5a1b3Sopenharmony_ci 10, 233753a5a1b3Sopenharmony_ci pa_rtclock_now(), 233853a5a1b3Sopenharmony_ci false); 233953a5a1b3Sopenharmony_ci#endif 234053a5a1b3Sopenharmony_ci u->ctag = 1; 234153a5a1b3Sopenharmony_ci u->device_index = u->channel = PA_INVALID_INDEX; 234253a5a1b3Sopenharmony_ci u->time_event = NULL; 234353a5a1b3Sopenharmony_ci u->ignore_latency_before = 0; 234453a5a1b3Sopenharmony_ci u->transport_usec = u->thread_transport_usec = 0; 234553a5a1b3Sopenharmony_ci u->remote_suspended = u->remote_corked = false; 234653a5a1b3Sopenharmony_ci u->counter = 0; 234753a5a1b3Sopenharmony_ci u->receive_snapshot = 0; 234853a5a1b3Sopenharmony_ci u->receive_counter = 0; 234953a5a1b3Sopenharmony_ci 235053a5a1b3Sopenharmony_ci u->msg = pa_msgobject_new(tunnel_msg); 235153a5a1b3Sopenharmony_ci u->msg->parent.process_msg = tunnel_process_msg; 235253a5a1b3Sopenharmony_ci 235353a5a1b3Sopenharmony_ci u->rtpoll = pa_rtpoll_new(); 235453a5a1b3Sopenharmony_ci 235553a5a1b3Sopenharmony_ci if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { 235653a5a1b3Sopenharmony_ci pa_log("pa_thread_mq_init() failed."); 235753a5a1b3Sopenharmony_ci goto fail; 235853a5a1b3Sopenharmony_ci } 235953a5a1b3Sopenharmony_ci 236053a5a1b3Sopenharmony_ci automatic = false; 236153a5a1b3Sopenharmony_ci if (pa_modargs_get_value_boolean(ma, "auto", &automatic) < 0) { 236253a5a1b3Sopenharmony_ci pa_log("Failed to parse argument \"auto\"."); 236353a5a1b3Sopenharmony_ci goto fail; 236453a5a1b3Sopenharmony_ci } 236553a5a1b3Sopenharmony_ci 236653a5a1b3Sopenharmony_ci /* Allow latencies between 5ms and 500ms */ 236753a5a1b3Sopenharmony_ci latency_msec = DEFAULT_LATENCY_MSEC; 236853a5a1b3Sopenharmony_ci if (pa_modargs_get_value_u32(ma, "latency_msec", &latency_msec) < 0 || latency_msec < 5 || latency_msec > 500) { 236953a5a1b3Sopenharmony_ci pa_log("Invalid latency specification"); 237053a5a1b3Sopenharmony_ci goto fail; 237153a5a1b3Sopenharmony_ci } 237253a5a1b3Sopenharmony_ci 237353a5a1b3Sopenharmony_ci u->latency = latency_msec; 237453a5a1b3Sopenharmony_ci 237553a5a1b3Sopenharmony_ci cookie_path = pa_modargs_get_value(ma, "cookie", NULL); 237653a5a1b3Sopenharmony_ci server = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL)); 237753a5a1b3Sopenharmony_ci 237853a5a1b3Sopenharmony_ci if (automatic) { 237953a5a1b3Sopenharmony_ci#ifdef HAVE_X11 238053a5a1b3Sopenharmony_ci /* Need an X11 connection to get root properties */ 238153a5a1b3Sopenharmony_ci if (getenv("DISPLAY") != NULL) { 238253a5a1b3Sopenharmony_ci if (!(xcb = xcb_connect(getenv("DISPLAY"), NULL))) 238353a5a1b3Sopenharmony_ci pa_log("xcb_connect() failed"); 238453a5a1b3Sopenharmony_ci else { 238553a5a1b3Sopenharmony_ci if (xcb_connection_has_error(xcb)) { 238653a5a1b3Sopenharmony_ci pa_log("xcb_connection_has_error() returned true"); 238753a5a1b3Sopenharmony_ci xcb_disconnect(xcb); 238853a5a1b3Sopenharmony_ci xcb = NULL; 238953a5a1b3Sopenharmony_ci } 239053a5a1b3Sopenharmony_ci } 239153a5a1b3Sopenharmony_ci } 239253a5a1b3Sopenharmony_ci#endif 239353a5a1b3Sopenharmony_ci 239453a5a1b3Sopenharmony_ci /* Figure out the cookie the same way a normal client would */ 239553a5a1b3Sopenharmony_ci if (!cookie_path) 239653a5a1b3Sopenharmony_ci cookie_path = getenv(ENV_COOKIE_FILE); 239753a5a1b3Sopenharmony_ci 239853a5a1b3Sopenharmony_ci#ifdef HAVE_X11 239953a5a1b3Sopenharmony_ci if (!cookie_path && xcb) { 240053a5a1b3Sopenharmony_ci char t[1024]; 240153a5a1b3Sopenharmony_ci if (pa_x11_get_prop(xcb, 0, "PULSE_COOKIE", t, sizeof(t))) { 240253a5a1b3Sopenharmony_ci uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; 240353a5a1b3Sopenharmony_ci 240453a5a1b3Sopenharmony_ci if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) 240553a5a1b3Sopenharmony_ci pa_log("Failed to parse cookie data"); 240653a5a1b3Sopenharmony_ci else { 240753a5a1b3Sopenharmony_ci if (!(u->auth_cookie = pa_auth_cookie_create(u->core, cookie, sizeof(cookie)))) 240853a5a1b3Sopenharmony_ci goto fail; 240953a5a1b3Sopenharmony_ci } 241053a5a1b3Sopenharmony_ci } 241153a5a1b3Sopenharmony_ci } 241253a5a1b3Sopenharmony_ci#endif 241353a5a1b3Sopenharmony_ci 241453a5a1b3Sopenharmony_ci /* Same thing for the server name */ 241553a5a1b3Sopenharmony_ci if (!server) 241653a5a1b3Sopenharmony_ci server = pa_xstrdup(getenv(ENV_DEFAULT_SERVER)); 241753a5a1b3Sopenharmony_ci 241853a5a1b3Sopenharmony_ci#ifdef HAVE_X11 241953a5a1b3Sopenharmony_ci if (!server && xcb) { 242053a5a1b3Sopenharmony_ci char t[1024]; 242153a5a1b3Sopenharmony_ci if (pa_x11_get_prop(xcb, 0, "PULSE_SERVER", t, sizeof(t))) 242253a5a1b3Sopenharmony_ci server = pa_xstrdup(t); 242353a5a1b3Sopenharmony_ci } 242453a5a1b3Sopenharmony_ci#endif 242553a5a1b3Sopenharmony_ci 242653a5a1b3Sopenharmony_ci /* Also determine the default sink/source on the other server */ 242753a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 242853a5a1b3Sopenharmony_ci if (!u->sink_name) 242953a5a1b3Sopenharmony_ci u->sink_name = pa_xstrdup(getenv(ENV_DEFAULT_SINK)); 243053a5a1b3Sopenharmony_ci 243153a5a1b3Sopenharmony_ci#ifdef HAVE_X11 243253a5a1b3Sopenharmony_ci if (!u->sink_name && xcb) { 243353a5a1b3Sopenharmony_ci char t[1024]; 243453a5a1b3Sopenharmony_ci if (pa_x11_get_prop(xcb, 0, "PULSE_SINK", t, sizeof(t))) 243553a5a1b3Sopenharmony_ci u->sink_name = pa_xstrdup(t); 243653a5a1b3Sopenharmony_ci } 243753a5a1b3Sopenharmony_ci#endif 243853a5a1b3Sopenharmony_ci#else 243953a5a1b3Sopenharmony_ci if (!u->source_name) 244053a5a1b3Sopenharmony_ci u->source_name = pa_xstrdup(getenv(ENV_DEFAULT_SOURCE)); 244153a5a1b3Sopenharmony_ci 244253a5a1b3Sopenharmony_ci#ifdef HAVE_X11 244353a5a1b3Sopenharmony_ci if (!u->source_name && xcb) { 244453a5a1b3Sopenharmony_ci char t[1024]; 244553a5a1b3Sopenharmony_ci if (pa_x11_get_prop(xcb, 0, "PULSE_SOURCE", t, sizeof(t))) 244653a5a1b3Sopenharmony_ci u->source_name = pa_xstrdup(t); 244753a5a1b3Sopenharmony_ci } 244853a5a1b3Sopenharmony_ci#endif 244953a5a1b3Sopenharmony_ci#endif 245053a5a1b3Sopenharmony_ci } 245153a5a1b3Sopenharmony_ci 245253a5a1b3Sopenharmony_ci if (!cookie_path && !u->auth_cookie) 245353a5a1b3Sopenharmony_ci cookie_path = PA_NATIVE_COOKIE_FILE; 245453a5a1b3Sopenharmony_ci 245553a5a1b3Sopenharmony_ci if (cookie_path) { 245653a5a1b3Sopenharmony_ci if (!(u->auth_cookie = pa_auth_cookie_get(u->core, cookie_path, true, PA_NATIVE_COOKIE_LENGTH))) 245753a5a1b3Sopenharmony_ci goto fail; 245853a5a1b3Sopenharmony_ci } 245953a5a1b3Sopenharmony_ci 246053a5a1b3Sopenharmony_ci u->sample_spec = m->core->default_sample_spec; 246153a5a1b3Sopenharmony_ci u->channel_map = m->core->default_channel_map; 246253a5a1b3Sopenharmony_ci if (pa_modargs_get_sample_spec_and_channel_map(ma, &u->sample_spec, &u->channel_map, PA_CHANNEL_MAP_DEFAULT) < 0) { 246353a5a1b3Sopenharmony_ci pa_log("Invalid sample format specification"); 246453a5a1b3Sopenharmony_ci goto fail; 246553a5a1b3Sopenharmony_ci } 246653a5a1b3Sopenharmony_ci 246753a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 246853a5a1b3Sopenharmony_ci /* Smoother window must be larger than time between updates. */ 246953a5a1b3Sopenharmony_ci u->smoother = pa_smoother_2_new(LATENCY_INTERVAL + 5*PA_USEC_PER_SEC, pa_rtclock_now(), pa_frame_size(&u->sample_spec), u->sample_spec.rate); 247053a5a1b3Sopenharmony_ci#endif 247153a5a1b3Sopenharmony_ci 247253a5a1b3Sopenharmony_ci pa_modargs_get_value_u32(ma, "reconnect_interval_ms", &reconnect_interval_ms); 247353a5a1b3Sopenharmony_ci u->reconnect_interval_us = reconnect_interval_ms * PA_USEC_PER_MSEC; 247453a5a1b3Sopenharmony_ci 247553a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 247653a5a1b3Sopenharmony_ci 247753a5a1b3Sopenharmony_ci u->sink_proplist = pa_proplist_new(); 247853a5a1b3Sopenharmony_ci if (pa_modargs_get_proplist(ma, "sink_properties", u->sink_proplist, PA_UPDATE_REPLACE) < 0) { 247953a5a1b3Sopenharmony_ci pa_log("Invalid properties"); 248053a5a1b3Sopenharmony_ci goto fail; 248153a5a1b3Sopenharmony_ci } 248253a5a1b3Sopenharmony_ci 248353a5a1b3Sopenharmony_ci#else 248453a5a1b3Sopenharmony_ci 248553a5a1b3Sopenharmony_ci u->source_proplist = pa_proplist_new(); 248653a5a1b3Sopenharmony_ci if (pa_modargs_get_proplist(ma, "source_properties", u->source_proplist, PA_UPDATE_REPLACE) < 0) { 248753a5a1b3Sopenharmony_ci pa_log("Invalid properties"); 248853a5a1b3Sopenharmony_ci goto fail; 248953a5a1b3Sopenharmony_ci } 249053a5a1b3Sopenharmony_ci 249153a5a1b3Sopenharmony_ci#endif 249253a5a1b3Sopenharmony_ci 249353a5a1b3Sopenharmony_ci u->time_event = NULL; 249453a5a1b3Sopenharmony_ci 249553a5a1b3Sopenharmony_ci u->maxlength = (uint32_t) -1; 249653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 249753a5a1b3Sopenharmony_ci u->tlength = u->minreq = u->prebuf = (uint32_t) -1; 249853a5a1b3Sopenharmony_ci#else 249953a5a1b3Sopenharmony_ci u->fragsize = (uint32_t) -1; 250053a5a1b3Sopenharmony_ci#endif 250153a5a1b3Sopenharmony_ci 250253a5a1b3Sopenharmony_ci if (start_connect(u, server, automatic) < 0) { 250353a5a1b3Sopenharmony_ci goto fail; 250453a5a1b3Sopenharmony_ci } 250553a5a1b3Sopenharmony_ci 250653a5a1b3Sopenharmony_ci if (!(u->thread = pa_thread_new("module-tunnel", thread_func, u))) { 250753a5a1b3Sopenharmony_ci pa_log("Failed to create thread."); 250853a5a1b3Sopenharmony_ci goto fail; 250953a5a1b3Sopenharmony_ci } 251053a5a1b3Sopenharmony_ci 251153a5a1b3Sopenharmony_ci if (server) 251253a5a1b3Sopenharmony_ci pa_xfree(server); 251353a5a1b3Sopenharmony_ci 251453a5a1b3Sopenharmony_ci#ifdef HAVE_X11 251553a5a1b3Sopenharmony_ci if (xcb) 251653a5a1b3Sopenharmony_ci xcb_disconnect(xcb); 251753a5a1b3Sopenharmony_ci#endif 251853a5a1b3Sopenharmony_ci 251953a5a1b3Sopenharmony_ci /* If the module is restarting and do_init() finishes successfully, the 252053a5a1b3Sopenharmony_ci * restart data is no longer needed. If do_init() fails, don't touch the 252153a5a1b3Sopenharmony_ci * restart data, because following restart attempts will continue to use 252253a5a1b3Sopenharmony_ci * the same data. If restart_data is NULL, that means no restart is 252353a5a1b3Sopenharmony_ci * currently pending. */ 252453a5a1b3Sopenharmony_ci if (rd->restart_data) { 252553a5a1b3Sopenharmony_ci pa_restart_free(rd->restart_data); 252653a5a1b3Sopenharmony_ci rd->restart_data = NULL; 252753a5a1b3Sopenharmony_ci } 252853a5a1b3Sopenharmony_ci 252953a5a1b3Sopenharmony_ci pa_modargs_free(ma); 253053a5a1b3Sopenharmony_ci 253153a5a1b3Sopenharmony_ci return 0; 253253a5a1b3Sopenharmony_ci 253353a5a1b3Sopenharmony_cifail: 253453a5a1b3Sopenharmony_ci if (server) 253553a5a1b3Sopenharmony_ci pa_xfree(server); 253653a5a1b3Sopenharmony_ci 253753a5a1b3Sopenharmony_ci#ifdef HAVE_X11 253853a5a1b3Sopenharmony_ci if (xcb) 253953a5a1b3Sopenharmony_ci xcb_disconnect(xcb); 254053a5a1b3Sopenharmony_ci#endif 254153a5a1b3Sopenharmony_ci 254253a5a1b3Sopenharmony_ci if (ma) 254353a5a1b3Sopenharmony_ci pa_modargs_free(ma); 254453a5a1b3Sopenharmony_ci 254553a5a1b3Sopenharmony_ci return -1; 254653a5a1b3Sopenharmony_ci} 254753a5a1b3Sopenharmony_ci 254853a5a1b3Sopenharmony_cistatic void do_done(pa_module *m) { 254953a5a1b3Sopenharmony_ci struct userdata *u = NULL; 255053a5a1b3Sopenharmony_ci struct module_restart_data *rd; 255153a5a1b3Sopenharmony_ci 255253a5a1b3Sopenharmony_ci pa_assert(m); 255353a5a1b3Sopenharmony_ci 255453a5a1b3Sopenharmony_ci if (!(rd = m->userdata)) 255553a5a1b3Sopenharmony_ci return; 255653a5a1b3Sopenharmony_ci if (!(u = rd->userdata)) 255753a5a1b3Sopenharmony_ci return; 255853a5a1b3Sopenharmony_ci 255953a5a1b3Sopenharmony_ci u->shutting_down = true; 256053a5a1b3Sopenharmony_ci 256153a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 256253a5a1b3Sopenharmony_ci if (u->sink) 256353a5a1b3Sopenharmony_ci pa_sink_unlink(u->sink); 256453a5a1b3Sopenharmony_ci#else 256553a5a1b3Sopenharmony_ci if (u->source) 256653a5a1b3Sopenharmony_ci pa_source_unlink(u->source); 256753a5a1b3Sopenharmony_ci#endif 256853a5a1b3Sopenharmony_ci 256953a5a1b3Sopenharmony_ci if (u->thread) { 257053a5a1b3Sopenharmony_ci pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); 257153a5a1b3Sopenharmony_ci pa_thread_free(u->thread); 257253a5a1b3Sopenharmony_ci } 257353a5a1b3Sopenharmony_ci 257453a5a1b3Sopenharmony_ci pa_thread_mq_done(&u->thread_mq); 257553a5a1b3Sopenharmony_ci 257653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 257753a5a1b3Sopenharmony_ci if (u->sink) 257853a5a1b3Sopenharmony_ci pa_sink_unref(u->sink); 257953a5a1b3Sopenharmony_ci#else 258053a5a1b3Sopenharmony_ci if (u->source) 258153a5a1b3Sopenharmony_ci pa_source_unref(u->source); 258253a5a1b3Sopenharmony_ci#endif 258353a5a1b3Sopenharmony_ci 258453a5a1b3Sopenharmony_ci if (u->rtpoll) 258553a5a1b3Sopenharmony_ci pa_rtpoll_free(u->rtpoll); 258653a5a1b3Sopenharmony_ci 258753a5a1b3Sopenharmony_ci if (u->pstream) { 258853a5a1b3Sopenharmony_ci pa_pstream_unlink(u->pstream); 258953a5a1b3Sopenharmony_ci pa_pstream_unref(u->pstream); 259053a5a1b3Sopenharmony_ci } 259153a5a1b3Sopenharmony_ci 259253a5a1b3Sopenharmony_ci if (u->pdispatch) 259353a5a1b3Sopenharmony_ci pa_pdispatch_unref(u->pdispatch); 259453a5a1b3Sopenharmony_ci 259553a5a1b3Sopenharmony_ci if (u->client) 259653a5a1b3Sopenharmony_ci pa_socket_client_unref(u->client); 259753a5a1b3Sopenharmony_ci 259853a5a1b3Sopenharmony_ci if (u->auth_cookie) 259953a5a1b3Sopenharmony_ci pa_auth_cookie_unref(u->auth_cookie); 260053a5a1b3Sopenharmony_ci 260153a5a1b3Sopenharmony_ci if (u->smoother) 260253a5a1b3Sopenharmony_ci#ifdef USE_SMOOTHER_2 260353a5a1b3Sopenharmony_ci pa_smoother_2_free(u->smoother); 260453a5a1b3Sopenharmony_ci#else 260553a5a1b3Sopenharmony_ci pa_smoother_free(u->smoother); 260653a5a1b3Sopenharmony_ci#endif 260753a5a1b3Sopenharmony_ci 260853a5a1b3Sopenharmony_ci if (u->time_event) 260953a5a1b3Sopenharmony_ci u->core->mainloop->time_free(u->time_event); 261053a5a1b3Sopenharmony_ci 261153a5a1b3Sopenharmony_ci#ifndef TUNNEL_SINK 261253a5a1b3Sopenharmony_ci if (u->mcalign) 261353a5a1b3Sopenharmony_ci pa_mcalign_free(u->mcalign); 261453a5a1b3Sopenharmony_ci#endif 261553a5a1b3Sopenharmony_ci 261653a5a1b3Sopenharmony_ci#ifdef TUNNEL_SINK 261753a5a1b3Sopenharmony_ci pa_xfree(u->sink_name); 261853a5a1b3Sopenharmony_ci pa_xfree(u->configured_sink_name); 261953a5a1b3Sopenharmony_ci pa_proplist_free(u->sink_proplist); 262053a5a1b3Sopenharmony_ci#else 262153a5a1b3Sopenharmony_ci pa_xfree(u->source_name); 262253a5a1b3Sopenharmony_ci pa_xfree(u->configured_source_name); 262353a5a1b3Sopenharmony_ci pa_proplist_free(u->source_proplist); 262453a5a1b3Sopenharmony_ci#endif 262553a5a1b3Sopenharmony_ci pa_xfree(u->server_name); 262653a5a1b3Sopenharmony_ci 262753a5a1b3Sopenharmony_ci pa_xfree(u->device_description); 262853a5a1b3Sopenharmony_ci pa_xfree(u->server_fqdn); 262953a5a1b3Sopenharmony_ci pa_xfree(u->user_name); 263053a5a1b3Sopenharmony_ci 263153a5a1b3Sopenharmony_ci pa_xfree(u->msg); 263253a5a1b3Sopenharmony_ci 263353a5a1b3Sopenharmony_ci pa_xfree(u); 263453a5a1b3Sopenharmony_ci 263553a5a1b3Sopenharmony_ci rd->userdata = NULL; 263653a5a1b3Sopenharmony_ci} 263753a5a1b3Sopenharmony_ci 263853a5a1b3Sopenharmony_ciint pa__init(pa_module *m) { 263953a5a1b3Sopenharmony_ci int ret; 264053a5a1b3Sopenharmony_ci 264153a5a1b3Sopenharmony_ci pa_assert(m); 264253a5a1b3Sopenharmony_ci 264353a5a1b3Sopenharmony_ci m->userdata = pa_xnew0(struct module_restart_data, 1); 264453a5a1b3Sopenharmony_ci 264553a5a1b3Sopenharmony_ci ret = do_init(m); 264653a5a1b3Sopenharmony_ci 264753a5a1b3Sopenharmony_ci if (ret < 0) 264853a5a1b3Sopenharmony_ci pa__done(m); 264953a5a1b3Sopenharmony_ci 265053a5a1b3Sopenharmony_ci return ret; 265153a5a1b3Sopenharmony_ci} 265253a5a1b3Sopenharmony_ci 265353a5a1b3Sopenharmony_civoid pa__done(pa_module *m) { 265453a5a1b3Sopenharmony_ci pa_assert(m); 265553a5a1b3Sopenharmony_ci 265653a5a1b3Sopenharmony_ci do_done(m); 265753a5a1b3Sopenharmony_ci 265853a5a1b3Sopenharmony_ci if (m->userdata) { 265953a5a1b3Sopenharmony_ci struct module_restart_data *rd = m->userdata; 266053a5a1b3Sopenharmony_ci 266153a5a1b3Sopenharmony_ci if (rd->restart_data) 266253a5a1b3Sopenharmony_ci pa_restart_free(rd->restart_data); 266353a5a1b3Sopenharmony_ci 266453a5a1b3Sopenharmony_ci pa_xfree(m->userdata); 266553a5a1b3Sopenharmony_ci } 266653a5a1b3Sopenharmony_ci} 2667