153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2008 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB 653a5a1b3Sopenharmony_ci 753a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 853a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 953a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1053a5a1b3Sopenharmony_ci or (at your option) any later version. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1353a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1453a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1553a5a1b3Sopenharmony_ci General Public License for more details. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1853a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1953a5a1b3Sopenharmony_ci***/ 2053a5a1b3Sopenharmony_ci 2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2253a5a1b3Sopenharmony_ci#include <config.h> 2353a5a1b3Sopenharmony_ci#endif 2453a5a1b3Sopenharmony_ci 2553a5a1b3Sopenharmony_ci#ifndef LOG_TAG 2653a5a1b3Sopenharmony_ci#define LOG_TAG "Context" 2753a5a1b3Sopenharmony_ci#endif 2853a5a1b3Sopenharmony_ci 2953a5a1b3Sopenharmony_ci#include <stdio.h> 3053a5a1b3Sopenharmony_ci#include <stdlib.h> 3153a5a1b3Sopenharmony_ci#include <string.h> 3253a5a1b3Sopenharmony_ci#include <sys/types.h> 3353a5a1b3Sopenharmony_ci#include <unistd.h> 3453a5a1b3Sopenharmony_ci#include <sys/stat.h> 3553a5a1b3Sopenharmony_ci#include <errno.h> 3653a5a1b3Sopenharmony_ci#include <signal.h> 3753a5a1b3Sopenharmony_ci 3853a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_WAIT_H 3953a5a1b3Sopenharmony_ci#include <sys/wait.h> 4053a5a1b3Sopenharmony_ci#endif 4153a5a1b3Sopenharmony_ci 4253a5a1b3Sopenharmony_ci#ifdef HAVE_NETDB_H 4353a5a1b3Sopenharmony_ci#include <netdb.h> 4453a5a1b3Sopenharmony_ci#endif 4553a5a1b3Sopenharmony_ci 4653a5a1b3Sopenharmony_ci#include <pulse/version.h> 4753a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 4853a5a1b3Sopenharmony_ci#include <pulse/util.h> 4953a5a1b3Sopenharmony_ci#include <pulse/mainloop.h> 5053a5a1b3Sopenharmony_ci#include <pulse/timeval.h> 5153a5a1b3Sopenharmony_ci#include <pulse/fork-detect.h> 5253a5a1b3Sopenharmony_ci#include <pulse/client-conf.h> 5353a5a1b3Sopenharmony_ci 5453a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 5553a5a1b3Sopenharmony_ci#include <pulsecore/i18n.h> 5653a5a1b3Sopenharmony_ci#include <pulsecore/native-common.h> 5753a5a1b3Sopenharmony_ci#include <pulsecore/pdispatch.h> 5853a5a1b3Sopenharmony_ci#include <pulsecore/pstream.h> 5953a5a1b3Sopenharmony_ci#include <pulsecore/hashmap.h> 6053a5a1b3Sopenharmony_ci#include <pulsecore/socket-client.h> 6153a5a1b3Sopenharmony_ci#include <pulsecore/pstream-util.h> 6253a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h> 6353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h> 6453a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 6553a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 6653a5a1b3Sopenharmony_ci#include <pulsecore/creds.h> 6753a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 6853a5a1b3Sopenharmony_ci#include <pulsecore/proplist-util.h> 6953a5a1b3Sopenharmony_ci 7053a5a1b3Sopenharmony_ci#include "internal.h" 7153a5a1b3Sopenharmony_ci#include "context.h" 7253a5a1b3Sopenharmony_ci 7353a5a1b3Sopenharmony_civoid pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 7453a5a1b3Sopenharmony_cistatic void pa_command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 7553a5a1b3Sopenharmony_cistatic void pa_command_disable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 7653a5a1b3Sopenharmony_cistatic void pa_command_register_memfd_shmid(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); 7753a5a1b3Sopenharmony_ci 7853a5a1b3Sopenharmony_cistatic const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { 7953a5a1b3Sopenharmony_ci [PA_COMMAND_REQUEST] = pa_command_request, 8053a5a1b3Sopenharmony_ci [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, 8153a5a1b3Sopenharmony_ci [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, 8253a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, 8353a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, 8453a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_MOVED] = pa_command_stream_moved, 8553a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved, 8653a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended, 8753a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended, 8853a5a1b3Sopenharmony_ci [PA_COMMAND_STARTED] = pa_command_stream_started, 8953a5a1b3Sopenharmony_ci [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event, 9053a5a1b3Sopenharmony_ci [PA_COMMAND_EXTENSION] = pa_command_extension, 9153a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event, 9253a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event, 9353a5a1b3Sopenharmony_ci [PA_COMMAND_CLIENT_EVENT] = pa_command_client_event, 9453a5a1b3Sopenharmony_ci [PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr, 9553a5a1b3Sopenharmony_ci [PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr, 9653a5a1b3Sopenharmony_ci [PA_COMMAND_ENABLE_SRBCHANNEL] = pa_command_enable_srbchannel, 9753a5a1b3Sopenharmony_ci [PA_COMMAND_DISABLE_SRBCHANNEL] = pa_command_disable_srbchannel, 9853a5a1b3Sopenharmony_ci [PA_COMMAND_REGISTER_MEMFD_SHMID] = pa_command_register_memfd_shmid, 9953a5a1b3Sopenharmony_ci [PA_COMMAND_UNDERFLOW_OHOS] = pa_command_overflow_or_underflow, 10053a5a1b3Sopenharmony_ci}; 10153a5a1b3Sopenharmony_cistatic void context_free(pa_context *c); 10253a5a1b3Sopenharmony_ci 10353a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 10453a5a1b3Sopenharmony_cistatic DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata); 10553a5a1b3Sopenharmony_ci#endif 10653a5a1b3Sopenharmony_ci 10753a5a1b3Sopenharmony_cipa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { 10853a5a1b3Sopenharmony_ci return pa_context_new_with_proplist(mainloop, name, NULL); 10953a5a1b3Sopenharmony_ci} 11053a5a1b3Sopenharmony_ci 11153a5a1b3Sopenharmony_cistatic void reset_callbacks(pa_context *c) { 11253a5a1b3Sopenharmony_ci pa_assert(c); 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci c->state_callback = NULL; 11553a5a1b3Sopenharmony_ci c->state_userdata = NULL; 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci c->subscribe_callback = NULL; 11853a5a1b3Sopenharmony_ci c->subscribe_userdata = NULL; 11953a5a1b3Sopenharmony_ci 12053a5a1b3Sopenharmony_ci c->event_callback = NULL; 12153a5a1b3Sopenharmony_ci c->event_userdata = NULL; 12253a5a1b3Sopenharmony_ci 12353a5a1b3Sopenharmony_ci c->ext_device_manager.callback = NULL; 12453a5a1b3Sopenharmony_ci c->ext_device_manager.userdata = NULL; 12553a5a1b3Sopenharmony_ci 12653a5a1b3Sopenharmony_ci c->ext_device_restore.callback = NULL; 12753a5a1b3Sopenharmony_ci c->ext_device_restore.userdata = NULL; 12853a5a1b3Sopenharmony_ci 12953a5a1b3Sopenharmony_ci c->ext_stream_restore.callback = NULL; 13053a5a1b3Sopenharmony_ci c->ext_stream_restore.userdata = NULL; 13153a5a1b3Sopenharmony_ci} 13253a5a1b3Sopenharmony_ci 13353a5a1b3Sopenharmony_cipa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, const pa_proplist *p) { 13453a5a1b3Sopenharmony_ci pa_context *c; 13553a5a1b3Sopenharmony_ci pa_mem_type_t type; 13653a5a1b3Sopenharmony_ci const char *force_disable_shm_str; 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci pa_assert(mainloop); 13953a5a1b3Sopenharmony_ci 14053a5a1b3Sopenharmony_ci if (pa_detect_fork()) 14153a5a1b3Sopenharmony_ci return NULL; 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci pa_init_i18n(); 14453a5a1b3Sopenharmony_ci 14553a5a1b3Sopenharmony_ci c = pa_xnew0(pa_context, 1); 14653a5a1b3Sopenharmony_ci PA_REFCNT_INIT(c); 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci c->error = pa_xnew0(pa_context_error, 1); 14953a5a1b3Sopenharmony_ci assert(c->error); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); 15253a5a1b3Sopenharmony_ci 15353a5a1b3Sopenharmony_ci if (name) 15453a5a1b3Sopenharmony_ci pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name); 15553a5a1b3Sopenharmony_ci 15653a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 15753a5a1b3Sopenharmony_ci c->system_bus = c->session_bus = NULL; 15853a5a1b3Sopenharmony_ci#endif 15953a5a1b3Sopenharmony_ci c->mainloop = mainloop; 16053a5a1b3Sopenharmony_ci c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); 16153a5a1b3Sopenharmony_ci c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); 16253a5a1b3Sopenharmony_ci c->client_index = PA_INVALID_INDEX; 16353a5a1b3Sopenharmony_ci c->use_rtclock = pa_mainloop_is_our_api(mainloop); 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_ci PA_LLIST_HEAD_INIT(pa_stream, c->streams); 16653a5a1b3Sopenharmony_ci PA_LLIST_HEAD_INIT(pa_operation, c->operations); 16753a5a1b3Sopenharmony_ci 16853a5a1b3Sopenharmony_ci c->error->error = PA_OK; 16953a5a1b3Sopenharmony_ci c->state = PA_CONTEXT_UNCONNECTED; 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci reset_callbacks(c); 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci#ifndef MSG_NOSIGNAL 17453a5a1b3Sopenharmony_ci#ifdef SIGPIPE 17553a5a1b3Sopenharmony_ci pa_check_signal_is_blocked(SIGPIPE); 17653a5a1b3Sopenharmony_ci#endif 17753a5a1b3Sopenharmony_ci#endif 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_ci c->conf = pa_client_conf_new(); 18053a5a1b3Sopenharmony_ci pa_client_conf_load(c->conf, true, true); 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci force_disable_shm_str = pa_proplist_gets(c->proplist, PA_PROP_CONTEXT_FORCE_DISABLE_SHM); 18353a5a1b3Sopenharmony_ci if (force_disable_shm_str) { 18453a5a1b3Sopenharmony_ci int b = pa_parse_boolean(force_disable_shm_str); 18553a5a1b3Sopenharmony_ci if (b < 0) { 18653a5a1b3Sopenharmony_ci pa_log_warn("Ignored invalid value for '%s' property: %s", PA_PROP_CONTEXT_FORCE_DISABLE_SHM, force_disable_shm_str); 18753a5a1b3Sopenharmony_ci } else if (b) { 18853a5a1b3Sopenharmony_ci c->conf->disable_shm = true; 18953a5a1b3Sopenharmony_ci } 19053a5a1b3Sopenharmony_ci } 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci c->srb_template.readfd = -1; 19353a5a1b3Sopenharmony_ci c->srb_template.writefd = -1; 19453a5a1b3Sopenharmony_ci 19553a5a1b3Sopenharmony_ci c->memfd_on_local = (!c->conf->disable_memfd && pa_memfd_is_locally_supported()); 19653a5a1b3Sopenharmony_ci 19753a5a1b3Sopenharmony_ci type = (c->conf->disable_shm) ? PA_MEM_TYPE_PRIVATE : 19853a5a1b3Sopenharmony_ci ((!c->memfd_on_local) ? 19953a5a1b3Sopenharmony_ci PA_MEM_TYPE_SHARED_POSIX : PA_MEM_TYPE_SHARED_MEMFD); 20053a5a1b3Sopenharmony_ci 20153a5a1b3Sopenharmony_ci if (!(c->mempool = pa_mempool_new(type, c->conf->shm_size, true))) { 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci if (!c->conf->disable_shm) { 20453a5a1b3Sopenharmony_ci pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal private one."); 20553a5a1b3Sopenharmony_ci c->mempool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, c->conf->shm_size, true); 20653a5a1b3Sopenharmony_ci } 20753a5a1b3Sopenharmony_ci 20853a5a1b3Sopenharmony_ci if (!c->mempool) { 20953a5a1b3Sopenharmony_ci context_free(c); 21053a5a1b3Sopenharmony_ci return NULL; 21153a5a1b3Sopenharmony_ci } 21253a5a1b3Sopenharmony_ci } 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci return c; 21553a5a1b3Sopenharmony_ci} 21653a5a1b3Sopenharmony_ci 21753a5a1b3Sopenharmony_cistatic void context_unlink(pa_context *c) { 21853a5a1b3Sopenharmony_ci pa_stream *s; 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci pa_assert(c); 22153a5a1b3Sopenharmony_ci 22253a5a1b3Sopenharmony_ci s = c->streams ? pa_stream_ref(c->streams) : NULL; 22353a5a1b3Sopenharmony_ci while (s) { 22453a5a1b3Sopenharmony_ci pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; 22553a5a1b3Sopenharmony_ci pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); 22653a5a1b3Sopenharmony_ci pa_stream_unref(s); 22753a5a1b3Sopenharmony_ci s = n; 22853a5a1b3Sopenharmony_ci } 22953a5a1b3Sopenharmony_ci 23053a5a1b3Sopenharmony_ci while (c->operations) 23153a5a1b3Sopenharmony_ci pa_operation_cancel(c->operations); 23253a5a1b3Sopenharmony_ci 23353a5a1b3Sopenharmony_ci if (c->pdispatch) { 23453a5a1b3Sopenharmony_ci pa_pdispatch_unref(c->pdispatch); 23553a5a1b3Sopenharmony_ci c->pdispatch = NULL; 23653a5a1b3Sopenharmony_ci } 23753a5a1b3Sopenharmony_ci 23853a5a1b3Sopenharmony_ci if (c->pstream) { 23953a5a1b3Sopenharmony_ci pa_pstream_unlink(c->pstream); 24053a5a1b3Sopenharmony_ci pa_pstream_unref(c->pstream); 24153a5a1b3Sopenharmony_ci c->pstream = NULL; 24253a5a1b3Sopenharmony_ci } 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_ci if (c->srb_template.memblock) { 24553a5a1b3Sopenharmony_ci pa_memblock_unref(c->srb_template.memblock); 24653a5a1b3Sopenharmony_ci c->srb_template.memblock = NULL; 24753a5a1b3Sopenharmony_ci } 24853a5a1b3Sopenharmony_ci 24953a5a1b3Sopenharmony_ci if (c->client) { 25053a5a1b3Sopenharmony_ci pa_socket_client_unref(c->client); 25153a5a1b3Sopenharmony_ci c->client = NULL; 25253a5a1b3Sopenharmony_ci } 25353a5a1b3Sopenharmony_ci 25453a5a1b3Sopenharmony_ci reset_callbacks(c); 25553a5a1b3Sopenharmony_ci} 25653a5a1b3Sopenharmony_ci 25753a5a1b3Sopenharmony_cistatic void context_free(pa_context *c) { 25853a5a1b3Sopenharmony_ci pa_assert(c); 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci context_unlink(c); 26153a5a1b3Sopenharmony_ci 26253a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 26353a5a1b3Sopenharmony_ci if (c->system_bus) { 26453a5a1b3Sopenharmony_ci if (c->filter_added) 26553a5a1b3Sopenharmony_ci dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->system_bus), filter_cb, c); 26653a5a1b3Sopenharmony_ci pa_dbus_wrap_connection_free(c->system_bus); 26753a5a1b3Sopenharmony_ci } 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci if (c->session_bus) { 27053a5a1b3Sopenharmony_ci if (c->filter_added) 27153a5a1b3Sopenharmony_ci dbus_connection_remove_filter(pa_dbus_wrap_connection_get(c->session_bus), filter_cb, c); 27253a5a1b3Sopenharmony_ci pa_dbus_wrap_connection_free(c->session_bus); 27353a5a1b3Sopenharmony_ci } 27453a5a1b3Sopenharmony_ci#endif 27553a5a1b3Sopenharmony_ci 27653a5a1b3Sopenharmony_ci if (c->record_streams) 27753a5a1b3Sopenharmony_ci pa_hashmap_free(c->record_streams); 27853a5a1b3Sopenharmony_ci if (c->playback_streams) 27953a5a1b3Sopenharmony_ci pa_hashmap_free(c->playback_streams); 28053a5a1b3Sopenharmony_ci 28153a5a1b3Sopenharmony_ci if (c->mempool) 28253a5a1b3Sopenharmony_ci pa_mempool_unref(c->mempool); 28353a5a1b3Sopenharmony_ci 28453a5a1b3Sopenharmony_ci if (c->conf) 28553a5a1b3Sopenharmony_ci pa_client_conf_free(c->conf); 28653a5a1b3Sopenharmony_ci 28753a5a1b3Sopenharmony_ci pa_strlist_free(c->server_list); 28853a5a1b3Sopenharmony_ci 28953a5a1b3Sopenharmony_ci if (c->proplist) 29053a5a1b3Sopenharmony_ci pa_proplist_free(c->proplist); 29153a5a1b3Sopenharmony_ci 29253a5a1b3Sopenharmony_ci pa_xfree(c->server); 29353a5a1b3Sopenharmony_ci pa_xfree(c->error); 29453a5a1b3Sopenharmony_ci pa_xfree(c); 29553a5a1b3Sopenharmony_ci} 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_cipa_context* pa_context_ref(pa_context *c) { 29853a5a1b3Sopenharmony_ci pa_assert(c); 29953a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 30053a5a1b3Sopenharmony_ci 30153a5a1b3Sopenharmony_ci PA_REFCNT_INC(c); 30253a5a1b3Sopenharmony_ci return c; 30353a5a1b3Sopenharmony_ci} 30453a5a1b3Sopenharmony_ci 30553a5a1b3Sopenharmony_civoid pa_context_unref(pa_context *c) { 30653a5a1b3Sopenharmony_ci pa_assert(c); 30753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 30853a5a1b3Sopenharmony_ci 30953a5a1b3Sopenharmony_ci if (PA_REFCNT_DEC(c) <= 0) 31053a5a1b3Sopenharmony_ci context_free(c); 31153a5a1b3Sopenharmony_ci} 31253a5a1b3Sopenharmony_ci 31353a5a1b3Sopenharmony_civoid pa_context_set_state(pa_context *c, pa_context_state_t st) { 31453a5a1b3Sopenharmony_ci pa_assert(c); 31553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 31653a5a1b3Sopenharmony_ci 31753a5a1b3Sopenharmony_ci if (c->state == st) 31853a5a1b3Sopenharmony_ci return; 31953a5a1b3Sopenharmony_ci 32053a5a1b3Sopenharmony_ci pa_context_ref(c); 32153a5a1b3Sopenharmony_ci 32253a5a1b3Sopenharmony_ci c->state = st; 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci if (c->state_callback) 32553a5a1b3Sopenharmony_ci c->state_callback(c, c->state_userdata); 32653a5a1b3Sopenharmony_ci 32753a5a1b3Sopenharmony_ci if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) 32853a5a1b3Sopenharmony_ci context_unlink(c); 32953a5a1b3Sopenharmony_ci 33053a5a1b3Sopenharmony_ci pa_context_unref(c); 33153a5a1b3Sopenharmony_ci} 33253a5a1b3Sopenharmony_ci 33353a5a1b3Sopenharmony_ciint pa_context_set_error(const pa_context *c, int error) { 33453a5a1b3Sopenharmony_ci pa_assert(error >= 0); 33553a5a1b3Sopenharmony_ci pa_assert(error < PA_ERR_MAX); 33653a5a1b3Sopenharmony_ci 33753a5a1b3Sopenharmony_ci if (c) 33853a5a1b3Sopenharmony_ci c->error->error = error; 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci return error; 34153a5a1b3Sopenharmony_ci} 34253a5a1b3Sopenharmony_ci 34353a5a1b3Sopenharmony_civoid pa_context_fail(pa_context *c, int error) { 34453a5a1b3Sopenharmony_ci pa_assert(c); 34553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 34653a5a1b3Sopenharmony_ci 34753a5a1b3Sopenharmony_ci pa_context_set_error(c, error); 34853a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_FAILED); 34953a5a1b3Sopenharmony_ci} 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_cistatic void pstream_die_callback(pa_pstream *p, void *userdata) { 35253a5a1b3Sopenharmony_ci pa_context *c = userdata; 35353a5a1b3Sopenharmony_ci 35453a5a1b3Sopenharmony_ci pa_assert(p); 35553a5a1b3Sopenharmony_ci pa_assert(c); 35653a5a1b3Sopenharmony_ci 35753a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); 35853a5a1b3Sopenharmony_ci} 35953a5a1b3Sopenharmony_ci 36053a5a1b3Sopenharmony_cistatic void pstream_packet_callback(pa_pstream *p, pa_packet *packet, pa_cmsg_ancil_data *ancil_data, void *userdata) { 36153a5a1b3Sopenharmony_ci pa_context *c = userdata; 36253a5a1b3Sopenharmony_ci 36353a5a1b3Sopenharmony_ci pa_assert(p); 36453a5a1b3Sopenharmony_ci pa_assert(packet); 36553a5a1b3Sopenharmony_ci pa_assert(c); 36653a5a1b3Sopenharmony_ci 36753a5a1b3Sopenharmony_ci pa_context_ref(c); 36853a5a1b3Sopenharmony_ci 36953a5a1b3Sopenharmony_ci if (pa_pdispatch_run(c->pdispatch, packet, ancil_data, c) < 0) 37053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 37153a5a1b3Sopenharmony_ci 37253a5a1b3Sopenharmony_ci pa_context_unref(c); 37353a5a1b3Sopenharmony_ci} 37453a5a1b3Sopenharmony_ci 37553a5a1b3Sopenharmony_cistatic void handle_srbchannel_memblock(pa_context *c, pa_memblock *memblock) { 37653a5a1b3Sopenharmony_ci pa_srbchannel *sr; 37753a5a1b3Sopenharmony_ci pa_tagstruct *t; 37853a5a1b3Sopenharmony_ci 37953a5a1b3Sopenharmony_ci pa_assert(c); 38053a5a1b3Sopenharmony_ci 38153a5a1b3Sopenharmony_ci /* Memblock sanity check */ 38253a5a1b3Sopenharmony_ci if (!memblock) { 38353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 38453a5a1b3Sopenharmony_ci return; 38553a5a1b3Sopenharmony_ci } else if (pa_memblock_is_read_only(memblock)) { 38653a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 38753a5a1b3Sopenharmony_ci return; 38853a5a1b3Sopenharmony_ci } else if (pa_memblock_is_ours(memblock)) { 38953a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 39053a5a1b3Sopenharmony_ci return; 39153a5a1b3Sopenharmony_ci } 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_ci /* Create the srbchannel */ 39453a5a1b3Sopenharmony_ci c->srb_template.memblock = memblock; 39553a5a1b3Sopenharmony_ci pa_memblock_ref(memblock); 39653a5a1b3Sopenharmony_ci sr = pa_srbchannel_new_from_template(c->mainloop, &c->srb_template); 39753a5a1b3Sopenharmony_ci if (!sr) { 39853a5a1b3Sopenharmony_ci pa_log_warn("Failed to create srbchannel from template"); 39953a5a1b3Sopenharmony_ci c->srb_template.readfd = -1; 40053a5a1b3Sopenharmony_ci c->srb_template.writefd = -1; 40153a5a1b3Sopenharmony_ci pa_memblock_unref(c->srb_template.memblock); 40253a5a1b3Sopenharmony_ci c->srb_template.memblock = NULL; 40353a5a1b3Sopenharmony_ci return; 40453a5a1b3Sopenharmony_ci } 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci /* Ack the enable command */ 40753a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 40853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_COMMAND_ENABLE_SRBCHANNEL); 40953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, c->srb_setup_tag); 41053a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 41153a5a1b3Sopenharmony_ci 41253a5a1b3Sopenharmony_ci /* ...and switch over */ 41353a5a1b3Sopenharmony_ci pa_pstream_set_srbchannel(c->pstream, sr); 41453a5a1b3Sopenharmony_ci} 41553a5a1b3Sopenharmony_ci 41653a5a1b3Sopenharmony_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) { 41753a5a1b3Sopenharmony_ci pa_context *c = userdata; 41853a5a1b3Sopenharmony_ci pa_stream *s; 41953a5a1b3Sopenharmony_ci 42053a5a1b3Sopenharmony_ci pa_assert(p); 42153a5a1b3Sopenharmony_ci pa_assert(chunk); 42253a5a1b3Sopenharmony_ci pa_assert(chunk->length > 0); 42353a5a1b3Sopenharmony_ci pa_assert(c); 42453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 42553a5a1b3Sopenharmony_ci 42653a5a1b3Sopenharmony_ci pa_context_ref(c); 42753a5a1b3Sopenharmony_ci 42853a5a1b3Sopenharmony_ci if (c->srb_template.readfd != -1 && c->srb_template.memblock == NULL) { 42953a5a1b3Sopenharmony_ci handle_srbchannel_memblock(c, chunk->memblock); 43053a5a1b3Sopenharmony_ci pa_context_unref(c); 43153a5a1b3Sopenharmony_ci return; 43253a5a1b3Sopenharmony_ci } 43353a5a1b3Sopenharmony_ci 43453a5a1b3Sopenharmony_ci if ((s = pa_hashmap_get(c->record_streams, PA_UINT32_TO_PTR(channel)))) { 43553a5a1b3Sopenharmony_ci 43653a5a1b3Sopenharmony_ci if (chunk->memblock) { 43753a5a1b3Sopenharmony_ci pa_memblockq_seek(s->record_memblockq, offset, seek, true); 43853a5a1b3Sopenharmony_ci pa_memblockq_push_align(s->record_memblockq, chunk); 43953a5a1b3Sopenharmony_ci } else 44053a5a1b3Sopenharmony_ci pa_memblockq_seek(s->record_memblockq, offset+chunk->length, seek, true); 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ci if (s->read_callback) { 44353a5a1b3Sopenharmony_ci size_t l; 44453a5a1b3Sopenharmony_ci 44553a5a1b3Sopenharmony_ci if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0) 44653a5a1b3Sopenharmony_ci s->read_callback(s, l, s->read_userdata); 44753a5a1b3Sopenharmony_ci } 44853a5a1b3Sopenharmony_ci } 44953a5a1b3Sopenharmony_ci 45053a5a1b3Sopenharmony_ci pa_context_unref(c); 45153a5a1b3Sopenharmony_ci} 45253a5a1b3Sopenharmony_ci 45353a5a1b3Sopenharmony_ciint pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, bool fail) { 45453a5a1b3Sopenharmony_ci uint32_t err; 45553a5a1b3Sopenharmony_ci pa_assert(c); 45653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci if (command == PA_COMMAND_ERROR) { 45953a5a1b3Sopenharmony_ci pa_assert(t); 46053a5a1b3Sopenharmony_ci 46153a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &err) < 0 || 46253a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 46353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 46453a5a1b3Sopenharmony_ci return -1; 46553a5a1b3Sopenharmony_ci } 46653a5a1b3Sopenharmony_ci 46753a5a1b3Sopenharmony_ci } else if (command == PA_COMMAND_TIMEOUT) 46853a5a1b3Sopenharmony_ci err = PA_ERR_TIMEOUT; 46953a5a1b3Sopenharmony_ci else { 47053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 47153a5a1b3Sopenharmony_ci return -1; 47253a5a1b3Sopenharmony_ci } 47353a5a1b3Sopenharmony_ci 47453a5a1b3Sopenharmony_ci if (err == PA_OK) { 47553a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 47653a5a1b3Sopenharmony_ci return -1; 47753a5a1b3Sopenharmony_ci } 47853a5a1b3Sopenharmony_ci 47953a5a1b3Sopenharmony_ci if (err >= PA_ERR_MAX) 48053a5a1b3Sopenharmony_ci err = PA_ERR_UNKNOWN; 48153a5a1b3Sopenharmony_ci 48253a5a1b3Sopenharmony_ci if (fail) { 48353a5a1b3Sopenharmony_ci pa_context_fail(c, (int) err); 48453a5a1b3Sopenharmony_ci return -1; 48553a5a1b3Sopenharmony_ci } 48653a5a1b3Sopenharmony_ci 48753a5a1b3Sopenharmony_ci pa_context_set_error(c, (int) err); 48853a5a1b3Sopenharmony_ci 48953a5a1b3Sopenharmony_ci return 0; 49053a5a1b3Sopenharmony_ci} 49153a5a1b3Sopenharmony_ci 49253a5a1b3Sopenharmony_cistatic void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 49353a5a1b3Sopenharmony_ci pa_context *c = userdata; 49453a5a1b3Sopenharmony_ci 49553a5a1b3Sopenharmony_ci pa_assert(pd); 49653a5a1b3Sopenharmony_ci pa_assert(c); 49753a5a1b3Sopenharmony_ci pa_assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); 49853a5a1b3Sopenharmony_ci 49953a5a1b3Sopenharmony_ci pa_context_ref(c); 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 50253a5a1b3Sopenharmony_ci pa_context_handle_error(c, command, t, true); 50353a5a1b3Sopenharmony_ci goto finish; 50453a5a1b3Sopenharmony_ci } 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci switch(c->state) { 50753a5a1b3Sopenharmony_ci case PA_CONTEXT_AUTHORIZING: { 50853a5a1b3Sopenharmony_ci pa_tagstruct *reply; 50953a5a1b3Sopenharmony_ci bool shm_on_remote = false; 51053a5a1b3Sopenharmony_ci bool memfd_on_remote = false; 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &c->version) < 0 || 51353a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 51453a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 51553a5a1b3Sopenharmony_ci goto finish; 51653a5a1b3Sopenharmony_ci } 51753a5a1b3Sopenharmony_ci 51853a5a1b3Sopenharmony_ci /* Minimum supported version */ 51953a5a1b3Sopenharmony_ci if (c->version < 8) { 52053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_VERSION); 52153a5a1b3Sopenharmony_ci goto finish; 52253a5a1b3Sopenharmony_ci } 52353a5a1b3Sopenharmony_ci 52453a5a1b3Sopenharmony_ci /* Starting with protocol version 13 the MSB of the version 52553a5a1b3Sopenharmony_ci tag reflects if shm is available for this connection or 52653a5a1b3Sopenharmony_ci not. */ 52753a5a1b3Sopenharmony_ci if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 13) { 52853a5a1b3Sopenharmony_ci shm_on_remote = !!(c->version & PA_PROTOCOL_FLAG_SHM); 52953a5a1b3Sopenharmony_ci 53053a5a1b3Sopenharmony_ci /* Starting with protocol version 31, the second MSB of the version 53153a5a1b3Sopenharmony_ci * tag reflects whether memfd is supported on the other PA end. */ 53253a5a1b3Sopenharmony_ci if ((c->version & PA_PROTOCOL_VERSION_MASK) >= 31) 53353a5a1b3Sopenharmony_ci memfd_on_remote = !!(c->version & PA_PROTOCOL_FLAG_MEMFD); 53453a5a1b3Sopenharmony_ci 53553a5a1b3Sopenharmony_ci /* Reserve the two most-significant _bytes_ of the version tag 53653a5a1b3Sopenharmony_ci * for flags. */ 53753a5a1b3Sopenharmony_ci c->version &= PA_PROTOCOL_VERSION_MASK; 53853a5a1b3Sopenharmony_ci } 53953a5a1b3Sopenharmony_ci 54053a5a1b3Sopenharmony_ci pa_log_debug("Protocol version: remote %u, local %u", c->version, PA_PROTOCOL_VERSION); 54153a5a1b3Sopenharmony_ci 54253a5a1b3Sopenharmony_ci /* Enable shared memory support if possible */ 54353a5a1b3Sopenharmony_ci if (c->do_shm) 54453a5a1b3Sopenharmony_ci if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) 54553a5a1b3Sopenharmony_ci c->do_shm = false; 54653a5a1b3Sopenharmony_ci 54753a5a1b3Sopenharmony_ci if (c->do_shm) { 54853a5a1b3Sopenharmony_ci 54953a5a1b3Sopenharmony_ci /* Only enable SHM if both sides are owned by the same 55053a5a1b3Sopenharmony_ci * user. This is a security measure because otherwise 55153a5a1b3Sopenharmony_ci * data private to the user might leak. */ 55253a5a1b3Sopenharmony_ci 55353a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 55453a5a1b3Sopenharmony_ci const pa_creds *creds; 55553a5a1b3Sopenharmony_ci if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) 55653a5a1b3Sopenharmony_ci c->do_shm = false; 55753a5a1b3Sopenharmony_ci#endif 55853a5a1b3Sopenharmony_ci } 55953a5a1b3Sopenharmony_ci 56053a5a1b3Sopenharmony_ci pa_log_debug("Negotiated SHM: %s", pa_yes_no(c->do_shm)); 56153a5a1b3Sopenharmony_ci pa_pstream_enable_shm(c->pstream, c->do_shm); 56253a5a1b3Sopenharmony_ci 56353a5a1b3Sopenharmony_ci c->shm_type = PA_MEM_TYPE_PRIVATE; 56453a5a1b3Sopenharmony_ci if (c->do_shm) { 56553a5a1b3Sopenharmony_ci if (c->version >= 31 && memfd_on_remote && c->memfd_on_local) { 56653a5a1b3Sopenharmony_ci const char *reason; 56753a5a1b3Sopenharmony_ci 56853a5a1b3Sopenharmony_ci pa_pstream_enable_memfd(c->pstream); 56953a5a1b3Sopenharmony_ci if (pa_mempool_is_memfd_backed(c->mempool)) 57053a5a1b3Sopenharmony_ci if (pa_pstream_register_memfd_mempool(c->pstream, c->mempool, &reason)) 57153a5a1b3Sopenharmony_ci pa_log("Failed to regester memfd mempool. Reason: %s", reason); 57253a5a1b3Sopenharmony_ci 57353a5a1b3Sopenharmony_ci /* Even if memfd pool registration fails, the negotiated SHM type 57453a5a1b3Sopenharmony_ci * shall remain memfd as both endpoints claim to support it. */ 57553a5a1b3Sopenharmony_ci c->shm_type = PA_MEM_TYPE_SHARED_MEMFD; 57653a5a1b3Sopenharmony_ci } else 57753a5a1b3Sopenharmony_ci c->shm_type = PA_MEM_TYPE_SHARED_POSIX; 57853a5a1b3Sopenharmony_ci } 57953a5a1b3Sopenharmony_ci 58053a5a1b3Sopenharmony_ci pa_log_debug("Memfd possible: %s", pa_yes_no(c->memfd_on_local)); 58153a5a1b3Sopenharmony_ci pa_log_debug("Negotiated SHM type: %s", pa_mem_type_to_string(c->shm_type)); 58253a5a1b3Sopenharmony_ci 58353a5a1b3Sopenharmony_ci reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); 58453a5a1b3Sopenharmony_ci 58553a5a1b3Sopenharmony_ci if (c->version >= 13) { 58653a5a1b3Sopenharmony_ci pa_init_proplist(c->proplist); 58753a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(reply, c->proplist); 58853a5a1b3Sopenharmony_ci } else 58953a5a1b3Sopenharmony_ci pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME)); 59053a5a1b3Sopenharmony_ci 59153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, reply); 59253a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); 59353a5a1b3Sopenharmony_ci 59453a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); 59553a5a1b3Sopenharmony_ci break; 59653a5a1b3Sopenharmony_ci } 59753a5a1b3Sopenharmony_ci 59853a5a1b3Sopenharmony_ci case PA_CONTEXT_SETTING_NAME : 59953a5a1b3Sopenharmony_ci 60053a5a1b3Sopenharmony_ci if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 || 60153a5a1b3Sopenharmony_ci c->client_index == PA_INVALID_INDEX)) || 60253a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t)) { 60353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 60453a5a1b3Sopenharmony_ci goto finish; 60553a5a1b3Sopenharmony_ci } 60653a5a1b3Sopenharmony_ci 60753a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_READY); 60853a5a1b3Sopenharmony_ci break; 60953a5a1b3Sopenharmony_ci 61053a5a1b3Sopenharmony_ci default: 61153a5a1b3Sopenharmony_ci pa_assert_not_reached(); 61253a5a1b3Sopenharmony_ci } 61353a5a1b3Sopenharmony_ci 61453a5a1b3Sopenharmony_cifinish: 61553a5a1b3Sopenharmony_ci pa_context_unref(c); 61653a5a1b3Sopenharmony_ci} 61753a5a1b3Sopenharmony_ci 61853a5a1b3Sopenharmony_cistatic void setup_context(pa_context *c, pa_iochannel *io) { 61953a5a1b3Sopenharmony_ci uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; 62053a5a1b3Sopenharmony_ci pa_tagstruct *t; 62153a5a1b3Sopenharmony_ci uint32_t tag; 62253a5a1b3Sopenharmony_ci 62353a5a1b3Sopenharmony_ci pa_assert(c); 62453a5a1b3Sopenharmony_ci pa_assert(io); 62553a5a1b3Sopenharmony_ci 62653a5a1b3Sopenharmony_ci pa_context_ref(c); 62753a5a1b3Sopenharmony_ci 62853a5a1b3Sopenharmony_ci pa_assert(!c->pstream); 62953a5a1b3Sopenharmony_ci c->pstream = pa_pstream_new(c->mainloop, io, c->mempool); 63053a5a1b3Sopenharmony_ci 63153a5a1b3Sopenharmony_ci pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); 63253a5a1b3Sopenharmony_ci pa_pstream_set_receive_packet_callback(c->pstream, pstream_packet_callback, c); 63353a5a1b3Sopenharmony_ci pa_pstream_set_receive_memblock_callback(c->pstream, pstream_memblock_callback, c); 63453a5a1b3Sopenharmony_ci 63553a5a1b3Sopenharmony_ci pa_assert(!c->pdispatch); 63653a5a1b3Sopenharmony_ci c->pdispatch = pa_pdispatch_new(c->mainloop, c->use_rtclock, command_table, PA_COMMAND_MAX); 63753a5a1b3Sopenharmony_ci 63853a5a1b3Sopenharmony_ci if (pa_client_conf_load_cookie(c->conf, cookie, sizeof(cookie)) < 0) 63953a5a1b3Sopenharmony_ci pa_log_info("No cookie loaded. Attempting to connect without."); 64053a5a1b3Sopenharmony_ci 64153a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); 64253a5a1b3Sopenharmony_ci 64353a5a1b3Sopenharmony_ci c->do_shm = 64453a5a1b3Sopenharmony_ci pa_mempool_is_shared(c->mempool) && 64553a5a1b3Sopenharmony_ci c->is_local; 64653a5a1b3Sopenharmony_ci 64753a5a1b3Sopenharmony_ci pa_log_debug("SHM possible: %s", pa_yes_no(c->do_shm)); 64853a5a1b3Sopenharmony_ci 64953a5a1b3Sopenharmony_ci /* Starting with protocol version 13 we use the MSB of the version 65053a5a1b3Sopenharmony_ci * tag for informing the other side if we could do SHM or not. 65153a5a1b3Sopenharmony_ci * Starting from version 31, second MSB is used to flag memfd support. */ 65253a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION | (c->do_shm ? PA_PROTOCOL_FLAG_SHM : 0) | 65353a5a1b3Sopenharmony_ci (c->memfd_on_local ? PA_PROTOCOL_FLAG_MEMFD: 0)); 65453a5a1b3Sopenharmony_ci pa_tagstruct_put_arbitrary(t, cookie, sizeof(cookie)); 65553a5a1b3Sopenharmony_ci 65653a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 65753a5a1b3Sopenharmony_ci{ 65853a5a1b3Sopenharmony_ci pa_creds ucred; 65953a5a1b3Sopenharmony_ci 66053a5a1b3Sopenharmony_ci if (pa_iochannel_creds_supported(io)) 66153a5a1b3Sopenharmony_ci pa_iochannel_creds_enable(io); 66253a5a1b3Sopenharmony_ci 66353a5a1b3Sopenharmony_ci ucred.uid = getuid(); 66453a5a1b3Sopenharmony_ci ucred.gid = getgid(); 66553a5a1b3Sopenharmony_ci 66653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct_with_creds(c->pstream, t, &ucred); 66753a5a1b3Sopenharmony_ci} 66853a5a1b3Sopenharmony_ci#else 66953a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 67053a5a1b3Sopenharmony_ci#endif 67153a5a1b3Sopenharmony_ci 67253a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); 67353a5a1b3Sopenharmony_ci 67453a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); 67553a5a1b3Sopenharmony_ci 67653a5a1b3Sopenharmony_ci pa_context_unref(c); 67753a5a1b3Sopenharmony_ci} 67853a5a1b3Sopenharmony_ci 67953a5a1b3Sopenharmony_cistatic pa_strlist *prepend_per_user(pa_strlist *l) { 68053a5a1b3Sopenharmony_ci char *ufn; 68153a5a1b3Sopenharmony_ci 68253a5a1b3Sopenharmony_ci /* The per-user instance */ 68353a5a1b3Sopenharmony_ci if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) { 68453a5a1b3Sopenharmony_ci l = pa_strlist_prepend(l, ufn); 68553a5a1b3Sopenharmony_ci pa_xfree(ufn); 68653a5a1b3Sopenharmony_ci } 68753a5a1b3Sopenharmony_ci 68853a5a1b3Sopenharmony_ci return l; 68953a5a1b3Sopenharmony_ci} 69053a5a1b3Sopenharmony_ci 69153a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 69253a5a1b3Sopenharmony_ci 69353a5a1b3Sopenharmony_cistatic int context_autospawn(pa_context *c) { 69453a5a1b3Sopenharmony_ci pid_t pid; 69553a5a1b3Sopenharmony_ci int status, r; 69653a5a1b3Sopenharmony_ci struct sigaction sa; 69753a5a1b3Sopenharmony_ci 69853a5a1b3Sopenharmony_ci pa_context_ref(c); 69953a5a1b3Sopenharmony_ci 70053a5a1b3Sopenharmony_ci if (sigaction(SIGCHLD, NULL, &sa) < 0) { 70153a5a1b3Sopenharmony_ci pa_log_debug("sigaction() failed: %s", pa_cstrerror(errno)); 70253a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_INTERNAL); 70353a5a1b3Sopenharmony_ci goto fail; 70453a5a1b3Sopenharmony_ci } 70553a5a1b3Sopenharmony_ci 70653a5a1b3Sopenharmony_ci#ifdef SA_NOCLDWAIT 70753a5a1b3Sopenharmony_ci if ((sa.sa_flags & SA_NOCLDWAIT) || sa.sa_handler == SIG_IGN) { 70853a5a1b3Sopenharmony_ci#else 70953a5a1b3Sopenharmony_ci if (sa.sa_handler == SIG_IGN) { 71053a5a1b3Sopenharmony_ci#endif 71153a5a1b3Sopenharmony_ci pa_log_error("Process disabled waitpid(), cannot autospawn."); 71253a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); 71353a5a1b3Sopenharmony_ci goto fail; 71453a5a1b3Sopenharmony_ci } 71553a5a1b3Sopenharmony_ci 71653a5a1b3Sopenharmony_ci pa_log_debug("Trying to autospawn..."); 71753a5a1b3Sopenharmony_ci 71853a5a1b3Sopenharmony_ci if (c->spawn_api.prefork) 71953a5a1b3Sopenharmony_ci c->spawn_api.prefork(); 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci if ((pid = fork()) < 0) { 72253a5a1b3Sopenharmony_ci pa_log_error(_("fork(): %s"), pa_cstrerror(errno)); 72353a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_INTERNAL); 72453a5a1b3Sopenharmony_ci 72553a5a1b3Sopenharmony_ci if (c->spawn_api.postfork) 72653a5a1b3Sopenharmony_ci c->spawn_api.postfork(); 72753a5a1b3Sopenharmony_ci 72853a5a1b3Sopenharmony_ci goto fail; 72953a5a1b3Sopenharmony_ci } else if (!pid) { 73053a5a1b3Sopenharmony_ci /* Child */ 73153a5a1b3Sopenharmony_ci 73253a5a1b3Sopenharmony_ci const char *state = NULL; 73353a5a1b3Sopenharmony_ci const char * argv[32]; 73453a5a1b3Sopenharmony_ci unsigned n = 0; 73553a5a1b3Sopenharmony_ci 73653a5a1b3Sopenharmony_ci if (c->spawn_api.atfork) 73753a5a1b3Sopenharmony_ci c->spawn_api.atfork(); 73853a5a1b3Sopenharmony_ci 73953a5a1b3Sopenharmony_ci /* We leave most of the cleaning up of the process environment 74053a5a1b3Sopenharmony_ci * to the executable. We only clean up the file descriptors to 74153a5a1b3Sopenharmony_ci * make sure the executable can actually be loaded 74253a5a1b3Sopenharmony_ci * correctly. */ 74353a5a1b3Sopenharmony_ci pa_close_all(-1); 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_ci /* Setup argv */ 74653a5a1b3Sopenharmony_ci argv[n++] = c->conf->daemon_binary; 74753a5a1b3Sopenharmony_ci argv[n++] = "--start"; 74853a5a1b3Sopenharmony_ci 74953a5a1b3Sopenharmony_ci while (n < PA_ELEMENTSOF(argv)-1) { 75053a5a1b3Sopenharmony_ci char *a; 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) 75353a5a1b3Sopenharmony_ci break; 75453a5a1b3Sopenharmony_ci 75553a5a1b3Sopenharmony_ci argv[n++] = a; 75653a5a1b3Sopenharmony_ci } 75753a5a1b3Sopenharmony_ci 75853a5a1b3Sopenharmony_ci argv[n++] = NULL; 75953a5a1b3Sopenharmony_ci pa_assert(n <= PA_ELEMENTSOF(argv)); 76053a5a1b3Sopenharmony_ci 76153a5a1b3Sopenharmony_ci execv(argv[0], (char * const *) argv); 76253a5a1b3Sopenharmony_ci _exit(1); 76353a5a1b3Sopenharmony_ci } 76453a5a1b3Sopenharmony_ci 76553a5a1b3Sopenharmony_ci /* Parent */ 76653a5a1b3Sopenharmony_ci 76753a5a1b3Sopenharmony_ci if (c->spawn_api.postfork) 76853a5a1b3Sopenharmony_ci c->spawn_api.postfork(); 76953a5a1b3Sopenharmony_ci 77053a5a1b3Sopenharmony_ci do { 77153a5a1b3Sopenharmony_ci r = waitpid(pid, &status, 0); 77253a5a1b3Sopenharmony_ci } while (r < 0 && errno == EINTR); 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci if (r < 0) { 77553a5a1b3Sopenharmony_ci 77653a5a1b3Sopenharmony_ci if (errno != ECHILD) { 77753a5a1b3Sopenharmony_ci pa_log(_("waitpid(): %s"), pa_cstrerror(errno)); 77853a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_INTERNAL); 77953a5a1b3Sopenharmony_ci goto fail; 78053a5a1b3Sopenharmony_ci } 78153a5a1b3Sopenharmony_ci 78253a5a1b3Sopenharmony_ci /* hmm, something already reaped our child, so we assume 78353a5a1b3Sopenharmony_ci * startup worked, even if we cannot know */ 78453a5a1b3Sopenharmony_ci 78553a5a1b3Sopenharmony_ci } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { 78653a5a1b3Sopenharmony_ci pa_log_error("Connection refused for status"); 78753a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); 78853a5a1b3Sopenharmony_ci goto fail; 78953a5a1b3Sopenharmony_ci } 79053a5a1b3Sopenharmony_ci 79153a5a1b3Sopenharmony_ci pa_context_unref(c); 79253a5a1b3Sopenharmony_ci 79353a5a1b3Sopenharmony_ci return 0; 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_cifail: 79653a5a1b3Sopenharmony_ci 79753a5a1b3Sopenharmony_ci pa_context_unref(c); 79853a5a1b3Sopenharmony_ci 79953a5a1b3Sopenharmony_ci return -1; 80053a5a1b3Sopenharmony_ci} 80153a5a1b3Sopenharmony_ci 80253a5a1b3Sopenharmony_ci#endif /* OS_IS_WIN32 */ 80353a5a1b3Sopenharmony_ci 80453a5a1b3Sopenharmony_cistatic void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); 80553a5a1b3Sopenharmony_ci 80653a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 80753a5a1b3Sopenharmony_cistatic void track_pulseaudio_on_dbus(pa_context *c, DBusBusType type, pa_dbus_wrap_connection **conn) { 80853a5a1b3Sopenharmony_ci DBusError error; 80953a5a1b3Sopenharmony_ci 81053a5a1b3Sopenharmony_ci pa_assert(c); 81153a5a1b3Sopenharmony_ci pa_assert(conn); 81253a5a1b3Sopenharmony_ci 81353a5a1b3Sopenharmony_ci dbus_error_init(&error); 81453a5a1b3Sopenharmony_ci 81553a5a1b3Sopenharmony_ci if (!(*conn = pa_dbus_wrap_connection_new(c->mainloop, c->use_rtclock, type, &error)) || dbus_error_is_set(&error)) { 81653a5a1b3Sopenharmony_ci pa_log_warn("Unable to contact DBUS: %s: %s", error.name, error.message); 81753a5a1b3Sopenharmony_ci goto fail; 81853a5a1b3Sopenharmony_ci } 81953a5a1b3Sopenharmony_ci 82053a5a1b3Sopenharmony_ci if (!dbus_connection_add_filter(pa_dbus_wrap_connection_get(*conn), filter_cb, c, NULL)) { 82153a5a1b3Sopenharmony_ci pa_log_warn("Failed to add filter function"); 82253a5a1b3Sopenharmony_ci goto fail; 82353a5a1b3Sopenharmony_ci } 82453a5a1b3Sopenharmony_ci c->filter_added = true; 82553a5a1b3Sopenharmony_ci 82653a5a1b3Sopenharmony_ci if (pa_dbus_add_matches( 82753a5a1b3Sopenharmony_ci pa_dbus_wrap_connection_get(*conn), &error, 82853a5a1b3Sopenharmony_ci "type='signal',sender='" DBUS_SERVICE_DBUS "',interface='" DBUS_INTERFACE_DBUS "',member='NameOwnerChanged',arg0='org.pulseaudio.Server',arg1=''", NULL) < 0) { 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci pa_log_warn("Unable to track org.pulseaudio.Server: %s: %s", error.name, error.message); 83153a5a1b3Sopenharmony_ci goto fail; 83253a5a1b3Sopenharmony_ci } 83353a5a1b3Sopenharmony_ci 83453a5a1b3Sopenharmony_ci return; 83553a5a1b3Sopenharmony_ci 83653a5a1b3Sopenharmony_cifail: 83753a5a1b3Sopenharmony_ci if (*conn) { 83853a5a1b3Sopenharmony_ci pa_dbus_wrap_connection_free(*conn); 83953a5a1b3Sopenharmony_ci *conn = NULL; 84053a5a1b3Sopenharmony_ci } 84153a5a1b3Sopenharmony_ci 84253a5a1b3Sopenharmony_ci dbus_error_free(&error); 84353a5a1b3Sopenharmony_ci} 84453a5a1b3Sopenharmony_ci#endif 84553a5a1b3Sopenharmony_ci 84653a5a1b3Sopenharmony_cistatic int try_next_connection(pa_context *c) { 84753a5a1b3Sopenharmony_ci char *u = NULL; 84853a5a1b3Sopenharmony_ci int r = -1; 84953a5a1b3Sopenharmony_ci 85053a5a1b3Sopenharmony_ci pa_assert(c); 85153a5a1b3Sopenharmony_ci pa_assert(!c->client); 85253a5a1b3Sopenharmony_ci 85353a5a1b3Sopenharmony_ci for (;;) { 85453a5a1b3Sopenharmony_ci pa_xfree(u); 85553a5a1b3Sopenharmony_ci u = NULL; 85653a5a1b3Sopenharmony_ci 85753a5a1b3Sopenharmony_ci c->server_list = pa_strlist_pop(c->server_list, &u); 85853a5a1b3Sopenharmony_ci 85953a5a1b3Sopenharmony_ci if (!u) { 86053a5a1b3Sopenharmony_ci 86153a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 86253a5a1b3Sopenharmony_ci if (c->do_autospawn) { 86353a5a1b3Sopenharmony_ci 86453a5a1b3Sopenharmony_ci if ((r = context_autospawn(c)) < 0) 86553a5a1b3Sopenharmony_ci goto finish; 86653a5a1b3Sopenharmony_ci 86753a5a1b3Sopenharmony_ci /* Autospawn only once */ 86853a5a1b3Sopenharmony_ci c->do_autospawn = false; 86953a5a1b3Sopenharmony_ci 87053a5a1b3Sopenharmony_ci /* Connect only to per-user sockets this time */ 87153a5a1b3Sopenharmony_ci c->server_list = prepend_per_user(c->server_list); 87253a5a1b3Sopenharmony_ci 87353a5a1b3Sopenharmony_ci /* Retry connection */ 87453a5a1b3Sopenharmony_ci continue; 87553a5a1b3Sopenharmony_ci } 87653a5a1b3Sopenharmony_ci#endif 87753a5a1b3Sopenharmony_ci 87853a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 87953a5a1b3Sopenharmony_ci if (c->no_fail && !c->server_specified) { 88053a5a1b3Sopenharmony_ci if (!c->session_bus) 88153a5a1b3Sopenharmony_ci track_pulseaudio_on_dbus(c, DBUS_BUS_SESSION, &c->session_bus); 88253a5a1b3Sopenharmony_ci if (!c->system_bus) 88353a5a1b3Sopenharmony_ci track_pulseaudio_on_dbus(c, DBUS_BUS_SYSTEM, &c->system_bus); 88453a5a1b3Sopenharmony_ci 88553a5a1b3Sopenharmony_ci if (c->session_bus || c->system_bus) { 88653a5a1b3Sopenharmony_ci pa_log_debug("Waiting for PA on D-Bus..."); 88753a5a1b3Sopenharmony_ci break; 88853a5a1b3Sopenharmony_ci } 88953a5a1b3Sopenharmony_ci } else 89053a5a1b3Sopenharmony_ci#endif 89153a5a1b3Sopenharmony_ci pa_log_error("Connection refused for try connect"); 89253a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); 89353a5a1b3Sopenharmony_ci 89453a5a1b3Sopenharmony_ci goto finish; 89553a5a1b3Sopenharmony_ci } 89653a5a1b3Sopenharmony_ci 89753a5a1b3Sopenharmony_ci pa_log_debug("Trying to connect to %s...", u); 89853a5a1b3Sopenharmony_ci 89953a5a1b3Sopenharmony_ci pa_xfree(c->server); 90053a5a1b3Sopenharmony_ci c->server = pa_xstrdup(u); 90153a5a1b3Sopenharmony_ci 90253a5a1b3Sopenharmony_ci if (!(c->client = pa_socket_client_new_string(c->mainloop, c->use_rtclock, u, PA_NATIVE_DEFAULT_PORT))) 90353a5a1b3Sopenharmony_ci continue; 90453a5a1b3Sopenharmony_ci 90553a5a1b3Sopenharmony_ci c->is_local = pa_socket_client_is_local(c->client); 90653a5a1b3Sopenharmony_ci pa_socket_client_set_callback(c->client, on_connection, c); 90753a5a1b3Sopenharmony_ci break; 90853a5a1b3Sopenharmony_ci } 90953a5a1b3Sopenharmony_ci 91053a5a1b3Sopenharmony_ci r = 0; 91153a5a1b3Sopenharmony_ci 91253a5a1b3Sopenharmony_cifinish: 91353a5a1b3Sopenharmony_ci pa_xfree(u); 91453a5a1b3Sopenharmony_ci 91553a5a1b3Sopenharmony_ci return r; 91653a5a1b3Sopenharmony_ci} 91753a5a1b3Sopenharmony_ci 91853a5a1b3Sopenharmony_cistatic void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { 91953a5a1b3Sopenharmony_ci pa_context *c = userdata; 92053a5a1b3Sopenharmony_ci int saved_errno = errno; 92153a5a1b3Sopenharmony_ci 92253a5a1b3Sopenharmony_ci pa_assert(client); 92353a5a1b3Sopenharmony_ci pa_assert(c); 92453a5a1b3Sopenharmony_ci pa_assert(c->state == PA_CONTEXT_CONNECTING); 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_ci pa_context_ref(c); 92753a5a1b3Sopenharmony_ci 92853a5a1b3Sopenharmony_ci pa_socket_client_unref(client); 92953a5a1b3Sopenharmony_ci c->client = NULL; 93053a5a1b3Sopenharmony_ci 93153a5a1b3Sopenharmony_ci if (!io) { 93253a5a1b3Sopenharmony_ci /* Try the next item in the list */ 93353a5a1b3Sopenharmony_ci if (saved_errno == ECONNREFUSED || 93453a5a1b3Sopenharmony_ci saved_errno == ETIMEDOUT || 93553a5a1b3Sopenharmony_ci saved_errno == EHOSTUNREACH) { 93653a5a1b3Sopenharmony_ci try_next_connection(c); 93753a5a1b3Sopenharmony_ci goto finish; 93853a5a1b3Sopenharmony_ci } 93953a5a1b3Sopenharmony_ci 94053a5a1b3Sopenharmony_ci pa_log_error("Connection refused for io"); 94153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); 94253a5a1b3Sopenharmony_ci goto finish; 94353a5a1b3Sopenharmony_ci } 94453a5a1b3Sopenharmony_ci 94553a5a1b3Sopenharmony_ci setup_context(c, io); 94653a5a1b3Sopenharmony_ci 94753a5a1b3Sopenharmony_cifinish: 94853a5a1b3Sopenharmony_ci pa_context_unref(c); 94953a5a1b3Sopenharmony_ci} 95053a5a1b3Sopenharmony_ci 95153a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 95253a5a1b3Sopenharmony_cistatic DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) { 95353a5a1b3Sopenharmony_ci pa_context *c = userdata; 95453a5a1b3Sopenharmony_ci bool is_session; 95553a5a1b3Sopenharmony_ci 95653a5a1b3Sopenharmony_ci pa_assert(bus); 95753a5a1b3Sopenharmony_ci pa_assert(message); 95853a5a1b3Sopenharmony_ci pa_assert(c); 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci if (c->state != PA_CONTEXT_CONNECTING) 96153a5a1b3Sopenharmony_ci goto finish; 96253a5a1b3Sopenharmony_ci 96353a5a1b3Sopenharmony_ci if (!c->no_fail) 96453a5a1b3Sopenharmony_ci goto finish; 96553a5a1b3Sopenharmony_ci 96653a5a1b3Sopenharmony_ci /* FIXME: We probably should check if this is actually the NameOwnerChanged we were looking for */ 96753a5a1b3Sopenharmony_ci 96853a5a1b3Sopenharmony_ci is_session = c->session_bus && bus == pa_dbus_wrap_connection_get(c->session_bus); 96953a5a1b3Sopenharmony_ci pa_log_debug("Rock!! PulseAudio might be back on %s bus", is_session ? "session" : "system"); 97053a5a1b3Sopenharmony_ci 97153a5a1b3Sopenharmony_ci if (is_session) 97253a5a1b3Sopenharmony_ci /* The user instance via PF_LOCAL */ 97353a5a1b3Sopenharmony_ci c->server_list = prepend_per_user(c->server_list); 97453a5a1b3Sopenharmony_ci else 97553a5a1b3Sopenharmony_ci /* The system wide instance via PF_LOCAL */ 97653a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); 97753a5a1b3Sopenharmony_ci 97853a5a1b3Sopenharmony_ci if (!c->client) 97953a5a1b3Sopenharmony_ci try_next_connection(c); 98053a5a1b3Sopenharmony_ci 98153a5a1b3Sopenharmony_cifinish: 98253a5a1b3Sopenharmony_ci return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; 98353a5a1b3Sopenharmony_ci} 98453a5a1b3Sopenharmony_ci#endif 98553a5a1b3Sopenharmony_ci 98653a5a1b3Sopenharmony_ciint pa_context_connect( 98753a5a1b3Sopenharmony_ci pa_context *c, 98853a5a1b3Sopenharmony_ci const char *server, 98953a5a1b3Sopenharmony_ci pa_context_flags_t flags, 99053a5a1b3Sopenharmony_ci const pa_spawn_api *api) { 99153a5a1b3Sopenharmony_ci 99253a5a1b3Sopenharmony_ci int r = -1; 99353a5a1b3Sopenharmony_ci 99453a5a1b3Sopenharmony_ci pa_assert(c); 99553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 99653a5a1b3Sopenharmony_ci 99753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED); 99853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); 99953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !(flags & ~(PA_CONTEXT_NOAUTOSPAWN|PA_CONTEXT_NOFAIL)), PA_ERR_INVALID); 100053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); 100153a5a1b3Sopenharmony_ci 100253a5a1b3Sopenharmony_ci if (server) 100353a5a1b3Sopenharmony_ci c->conf->autospawn = false; 100453a5a1b3Sopenharmony_ci else 100553a5a1b3Sopenharmony_ci server = c->conf->default_server; 100653a5a1b3Sopenharmony_ci 100753a5a1b3Sopenharmony_ci pa_context_ref(c); 100853a5a1b3Sopenharmony_ci 100953a5a1b3Sopenharmony_ci c->no_fail = !!(flags & PA_CONTEXT_NOFAIL); 101053a5a1b3Sopenharmony_ci c->server_specified = !!server; 101153a5a1b3Sopenharmony_ci pa_assert(!c->server_list); 101253a5a1b3Sopenharmony_ci 101353a5a1b3Sopenharmony_ci if (server) { 101453a5a1b3Sopenharmony_ci if (!(c->server_list = pa_strlist_parse(server))) { 101553a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_INVALIDSERVER); 101653a5a1b3Sopenharmony_ci goto finish; 101753a5a1b3Sopenharmony_ci } 101853a5a1b3Sopenharmony_ci 101953a5a1b3Sopenharmony_ci } else { 102053a5a1b3Sopenharmony_ci char *d; 102153a5a1b3Sopenharmony_ci 102253a5a1b3Sopenharmony_ci /* Prepend in reverse order */ 102353a5a1b3Sopenharmony_ci 102453a5a1b3Sopenharmony_ci /* Follow the X display */ 102553a5a1b3Sopenharmony_ci if (c->conf->auto_connect_display) { 102653a5a1b3Sopenharmony_ci if ((d = getenv("DISPLAY"))) { 102753a5a1b3Sopenharmony_ci d = pa_xstrndup(d, strcspn(d, ":")); 102853a5a1b3Sopenharmony_ci 102953a5a1b3Sopenharmony_ci if (*d) 103053a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, d); 103153a5a1b3Sopenharmony_ci 103253a5a1b3Sopenharmony_ci pa_xfree(d); 103353a5a1b3Sopenharmony_ci } 103453a5a1b3Sopenharmony_ci } 103553a5a1b3Sopenharmony_ci 103653a5a1b3Sopenharmony_ci /* Add TCP/IP on the localhost */ 103753a5a1b3Sopenharmony_ci if (c->conf->auto_connect_localhost) { 103853a5a1b3Sopenharmony_ci#if defined(HAVE_IPV6) && !defined(OS_IS_WIN32) 103953a5a1b3Sopenharmony_ci /* FIXME: pa_socket_client does not support IPv6 on Windows */ 104053a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, "tcp6:[::1]"); 104153a5a1b3Sopenharmony_ci#endif 104253a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, "tcp4:127.0.0.1"); 104353a5a1b3Sopenharmony_ci } 104453a5a1b3Sopenharmony_ci 104553a5a1b3Sopenharmony_ci /* The system wide instance via PF_LOCAL */ 104653a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 104753a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET); 104853a5a1b3Sopenharmony_ci#else 104953a5a1b3Sopenharmony_ci /* see change_user in src/daemon/main.c */ 105053a5a1b3Sopenharmony_ci char *run_path = pa_sprintf_malloc("%s" PA_PATH_SEP "run" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, pa_win32_get_system_appdata()); 105153a5a1b3Sopenharmony_ci c->server_list = pa_strlist_prepend(c->server_list, run_path); 105253a5a1b3Sopenharmony_ci pa_xfree(run_path); 105353a5a1b3Sopenharmony_ci#endif 105453a5a1b3Sopenharmony_ci 105553a5a1b3Sopenharmony_ci /* The user instance via PF_LOCAL */ 105653a5a1b3Sopenharmony_ci c->server_list = prepend_per_user(c->server_list); 105753a5a1b3Sopenharmony_ci } 105853a5a1b3Sopenharmony_ci 105953a5a1b3Sopenharmony_ci /* Set up autospawning */ 106053a5a1b3Sopenharmony_ci if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { 106153a5a1b3Sopenharmony_ci 106253a5a1b3Sopenharmony_ci#ifdef HAVE_GETUID 106353a5a1b3Sopenharmony_ci if (getuid() == 0) 106453a5a1b3Sopenharmony_ci pa_log_debug("Not doing autospawn since we are root."); 106553a5a1b3Sopenharmony_ci else { 106653a5a1b3Sopenharmony_ci c->do_autospawn = true; 106753a5a1b3Sopenharmony_ci 106853a5a1b3Sopenharmony_ci if (api) 106953a5a1b3Sopenharmony_ci c->spawn_api = *api; 107053a5a1b3Sopenharmony_ci } 107153a5a1b3Sopenharmony_ci#endif 107253a5a1b3Sopenharmony_ci } 107353a5a1b3Sopenharmony_ci 107453a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_CONNECTING); 107553a5a1b3Sopenharmony_ci r = try_next_connection(c); 107653a5a1b3Sopenharmony_ci 107753a5a1b3Sopenharmony_cifinish: 107853a5a1b3Sopenharmony_ci pa_context_unref(c); 107953a5a1b3Sopenharmony_ci 108053a5a1b3Sopenharmony_ci return r; 108153a5a1b3Sopenharmony_ci} 108253a5a1b3Sopenharmony_ci 108353a5a1b3Sopenharmony_civoid pa_context_disconnect(pa_context *c) { 108453a5a1b3Sopenharmony_ci pa_assert(c); 108553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 108653a5a1b3Sopenharmony_ci 108753a5a1b3Sopenharmony_ci if (pa_detect_fork()) 108853a5a1b3Sopenharmony_ci return; 108953a5a1b3Sopenharmony_ci 109053a5a1b3Sopenharmony_ci if (PA_CONTEXT_IS_GOOD(c->state)) 109153a5a1b3Sopenharmony_ci pa_context_set_state(c, PA_CONTEXT_TERMINATED); 109253a5a1b3Sopenharmony_ci} 109353a5a1b3Sopenharmony_ci 109453a5a1b3Sopenharmony_cipa_context_state_t pa_context_get_state(const pa_context *c) { 109553a5a1b3Sopenharmony_ci pa_assert(c); 109653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 109753a5a1b3Sopenharmony_ci 109853a5a1b3Sopenharmony_ci return c->state; 109953a5a1b3Sopenharmony_ci} 110053a5a1b3Sopenharmony_ci 110153a5a1b3Sopenharmony_ciint pa_context_errno(const pa_context *c) { 110253a5a1b3Sopenharmony_ci 110353a5a1b3Sopenharmony_ci if (!c) 110453a5a1b3Sopenharmony_ci return PA_ERR_INVALID; 110553a5a1b3Sopenharmony_ci 110653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 110753a5a1b3Sopenharmony_ci 110853a5a1b3Sopenharmony_ci return c->error->error; 110953a5a1b3Sopenharmony_ci} 111053a5a1b3Sopenharmony_ci 111153a5a1b3Sopenharmony_civoid pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { 111253a5a1b3Sopenharmony_ci pa_assert(c); 111353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 111453a5a1b3Sopenharmony_ci 111553a5a1b3Sopenharmony_ci if (pa_detect_fork()) 111653a5a1b3Sopenharmony_ci return; 111753a5a1b3Sopenharmony_ci 111853a5a1b3Sopenharmony_ci if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED) 111953a5a1b3Sopenharmony_ci return; 112053a5a1b3Sopenharmony_ci 112153a5a1b3Sopenharmony_ci c->state_callback = cb; 112253a5a1b3Sopenharmony_ci c->state_userdata = userdata; 112353a5a1b3Sopenharmony_ci} 112453a5a1b3Sopenharmony_ci 112553a5a1b3Sopenharmony_civoid pa_context_set_event_callback(pa_context *c, pa_context_event_cb_t cb, void *userdata) { 112653a5a1b3Sopenharmony_ci pa_assert(c); 112753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 112853a5a1b3Sopenharmony_ci 112953a5a1b3Sopenharmony_ci if (pa_detect_fork()) 113053a5a1b3Sopenharmony_ci return; 113153a5a1b3Sopenharmony_ci 113253a5a1b3Sopenharmony_ci if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED) 113353a5a1b3Sopenharmony_ci return; 113453a5a1b3Sopenharmony_ci 113553a5a1b3Sopenharmony_ci c->event_callback = cb; 113653a5a1b3Sopenharmony_ci c->event_userdata = userdata; 113753a5a1b3Sopenharmony_ci} 113853a5a1b3Sopenharmony_ci 113953a5a1b3Sopenharmony_ciint pa_context_is_pending(const pa_context *c) { 114053a5a1b3Sopenharmony_ci pa_assert(c); 114153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 114253a5a1b3Sopenharmony_ci 114353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED); 114453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE); 114553a5a1b3Sopenharmony_ci 114653a5a1b3Sopenharmony_ci return (c->pstream && pa_pstream_is_pending(c->pstream)) || 114753a5a1b3Sopenharmony_ci (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || 114853a5a1b3Sopenharmony_ci c->client; 114953a5a1b3Sopenharmony_ci} 115053a5a1b3Sopenharmony_ci 115153a5a1b3Sopenharmony_cistatic void set_dispatch_callbacks(pa_operation *o); 115253a5a1b3Sopenharmony_ci 115353a5a1b3Sopenharmony_cistatic void pdispatch_drain_callback(pa_pdispatch*pd, void *userdata) { 115453a5a1b3Sopenharmony_ci set_dispatch_callbacks(userdata); 115553a5a1b3Sopenharmony_ci} 115653a5a1b3Sopenharmony_ci 115753a5a1b3Sopenharmony_cistatic void pstream_drain_callback(pa_pstream *s, void *userdata) { 115853a5a1b3Sopenharmony_ci set_dispatch_callbacks(userdata); 115953a5a1b3Sopenharmony_ci} 116053a5a1b3Sopenharmony_ci 116153a5a1b3Sopenharmony_cistatic void set_dispatch_callbacks(pa_operation *o) { 116253a5a1b3Sopenharmony_ci int done = 1; 116353a5a1b3Sopenharmony_ci 116453a5a1b3Sopenharmony_ci pa_assert(o); 116553a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 116653a5a1b3Sopenharmony_ci pa_assert(o->context); 116753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o->context) >= 1); 116853a5a1b3Sopenharmony_ci pa_assert(o->context->state == PA_CONTEXT_READY); 116953a5a1b3Sopenharmony_ci 117053a5a1b3Sopenharmony_ci pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); 117153a5a1b3Sopenharmony_ci pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); 117253a5a1b3Sopenharmony_ci 117353a5a1b3Sopenharmony_ci if (pa_pdispatch_is_pending(o->context->pdispatch)) { 117453a5a1b3Sopenharmony_ci pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); 117553a5a1b3Sopenharmony_ci done = 0; 117653a5a1b3Sopenharmony_ci } 117753a5a1b3Sopenharmony_ci 117853a5a1b3Sopenharmony_ci if (pa_pstream_is_pending(o->context->pstream)) { 117953a5a1b3Sopenharmony_ci pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); 118053a5a1b3Sopenharmony_ci done = 0; 118153a5a1b3Sopenharmony_ci } 118253a5a1b3Sopenharmony_ci 118353a5a1b3Sopenharmony_ci if (done) { 118453a5a1b3Sopenharmony_ci if (o->callback) { 118553a5a1b3Sopenharmony_ci pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; 118653a5a1b3Sopenharmony_ci cb(o->context, o->userdata); 118753a5a1b3Sopenharmony_ci } 118853a5a1b3Sopenharmony_ci 118953a5a1b3Sopenharmony_ci pa_operation_done(o); 119053a5a1b3Sopenharmony_ci pa_operation_unref(o); 119153a5a1b3Sopenharmony_ci } 119253a5a1b3Sopenharmony_ci} 119353a5a1b3Sopenharmony_ci 119453a5a1b3Sopenharmony_cipa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { 119553a5a1b3Sopenharmony_ci pa_operation *o; 119653a5a1b3Sopenharmony_ci 119753a5a1b3Sopenharmony_ci pa_assert(c); 119853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 119953a5a1b3Sopenharmony_ci 120053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 120153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 120253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); 120353a5a1b3Sopenharmony_ci 120453a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 120553a5a1b3Sopenharmony_ci set_dispatch_callbacks(pa_operation_ref(o)); 120653a5a1b3Sopenharmony_ci 120753a5a1b3Sopenharmony_ci return o; 120853a5a1b3Sopenharmony_ci} 120953a5a1b3Sopenharmony_ci 121053a5a1b3Sopenharmony_civoid pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 121153a5a1b3Sopenharmony_ci pa_operation *o = userdata; 121253a5a1b3Sopenharmony_ci int success = 1; 121353a5a1b3Sopenharmony_ci 121453a5a1b3Sopenharmony_ci pa_assert(pd); 121553a5a1b3Sopenharmony_ci pa_assert(o); 121653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(o) >= 1); 121753a5a1b3Sopenharmony_ci 121853a5a1b3Sopenharmony_ci if (!o->context) 121953a5a1b3Sopenharmony_ci goto finish; 122053a5a1b3Sopenharmony_ci 122153a5a1b3Sopenharmony_ci if (command != PA_COMMAND_REPLY) { 122253a5a1b3Sopenharmony_ci if (pa_context_handle_error(o->context, command, t, false) < 0) 122353a5a1b3Sopenharmony_ci goto finish; 122453a5a1b3Sopenharmony_ci 122553a5a1b3Sopenharmony_ci success = 0; 122653a5a1b3Sopenharmony_ci } else if (!pa_tagstruct_eof(t)) { 122753a5a1b3Sopenharmony_ci pa_context_fail(o->context, PA_ERR_PROTOCOL); 122853a5a1b3Sopenharmony_ci goto finish; 122953a5a1b3Sopenharmony_ci } 123053a5a1b3Sopenharmony_ci 123153a5a1b3Sopenharmony_ci if (o->callback) { 123253a5a1b3Sopenharmony_ci pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback; 123353a5a1b3Sopenharmony_ci cb(o->context, success, o->userdata); 123453a5a1b3Sopenharmony_ci } 123553a5a1b3Sopenharmony_ci 123653a5a1b3Sopenharmony_cifinish: 123753a5a1b3Sopenharmony_ci pa_operation_done(o); 123853a5a1b3Sopenharmony_ci pa_operation_unref(o); 123953a5a1b3Sopenharmony_ci} 124053a5a1b3Sopenharmony_ci 124153a5a1b3Sopenharmony_cipa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) { 124253a5a1b3Sopenharmony_ci pa_tagstruct *t; 124353a5a1b3Sopenharmony_ci pa_operation *o; 124453a5a1b3Sopenharmony_ci uint32_t tag; 124553a5a1b3Sopenharmony_ci 124653a5a1b3Sopenharmony_ci pa_assert(c); 124753a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 124853a5a1b3Sopenharmony_ci 124953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 125053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 125153a5a1b3Sopenharmony_ci 125253a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, cb, userdata); 125353a5a1b3Sopenharmony_ci 125453a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, command, &tag); 125553a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 125653a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 125753a5a1b3Sopenharmony_ci 125853a5a1b3Sopenharmony_ci return o; 125953a5a1b3Sopenharmony_ci} 126053a5a1b3Sopenharmony_ci 126153a5a1b3Sopenharmony_cipa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { 126253a5a1b3Sopenharmony_ci pa_assert(c); 126353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 126453a5a1b3Sopenharmony_ci 126553a5a1b3Sopenharmony_ci return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata); 126653a5a1b3Sopenharmony_ci} 126753a5a1b3Sopenharmony_ci 126853a5a1b3Sopenharmony_cipa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { 126953a5a1b3Sopenharmony_ci pa_tagstruct *t; 127053a5a1b3Sopenharmony_ci pa_operation *o; 127153a5a1b3Sopenharmony_ci uint32_t tag; 127253a5a1b3Sopenharmony_ci 127353a5a1b3Sopenharmony_ci pa_assert(c); 127453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 127553a5a1b3Sopenharmony_ci 127653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 127753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 127853a5a1b3Sopenharmony_ci 127953a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 128053a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); 128153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, name); 128253a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 128353a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 128453a5a1b3Sopenharmony_ci 128553a5a1b3Sopenharmony_ci return o; 128653a5a1b3Sopenharmony_ci} 128753a5a1b3Sopenharmony_ci 128853a5a1b3Sopenharmony_cipa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { 128953a5a1b3Sopenharmony_ci pa_tagstruct *t; 129053a5a1b3Sopenharmony_ci pa_operation *o; 129153a5a1b3Sopenharmony_ci uint32_t tag; 129253a5a1b3Sopenharmony_ci 129353a5a1b3Sopenharmony_ci pa_assert(c); 129453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 129553a5a1b3Sopenharmony_ci 129653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 129753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 129853a5a1b3Sopenharmony_ci 129953a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 130053a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); 130153a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, name); 130253a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 130353a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 130453a5a1b3Sopenharmony_ci 130553a5a1b3Sopenharmony_ci return o; 130653a5a1b3Sopenharmony_ci} 130753a5a1b3Sopenharmony_ci 130853a5a1b3Sopenharmony_ciint pa_context_is_local(const pa_context *c) { 130953a5a1b3Sopenharmony_ci pa_assert(c); 131053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 131153a5a1b3Sopenharmony_ci 131253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, -1); 131353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1); 131453a5a1b3Sopenharmony_ci 131553a5a1b3Sopenharmony_ci return c->is_local; 131653a5a1b3Sopenharmony_ci} 131753a5a1b3Sopenharmony_ci 131853a5a1b3Sopenharmony_cipa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { 131953a5a1b3Sopenharmony_ci pa_operation *o; 132053a5a1b3Sopenharmony_ci 132153a5a1b3Sopenharmony_ci pa_assert(c); 132253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 132353a5a1b3Sopenharmony_ci pa_assert(name); 132453a5a1b3Sopenharmony_ci 132553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 132653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 132753a5a1b3Sopenharmony_ci 132853a5a1b3Sopenharmony_ci if (c->version >= 13) { 132953a5a1b3Sopenharmony_ci pa_proplist *p = pa_proplist_new(); 133053a5a1b3Sopenharmony_ci 133153a5a1b3Sopenharmony_ci pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name); 133253a5a1b3Sopenharmony_ci o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata); 133353a5a1b3Sopenharmony_ci pa_proplist_free(p); 133453a5a1b3Sopenharmony_ci } else { 133553a5a1b3Sopenharmony_ci pa_tagstruct *t; 133653a5a1b3Sopenharmony_ci uint32_t tag; 133753a5a1b3Sopenharmony_ci 133853a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 133953a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); 134053a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, name); 134153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 134253a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 134353a5a1b3Sopenharmony_ci } 134453a5a1b3Sopenharmony_ci 134553a5a1b3Sopenharmony_ci return o; 134653a5a1b3Sopenharmony_ci} 134753a5a1b3Sopenharmony_ci 134853a5a1b3Sopenharmony_ciconst char* pa_get_library_version(void) { 134953a5a1b3Sopenharmony_ci return pa_get_headers_version(); 135053a5a1b3Sopenharmony_ci} 135153a5a1b3Sopenharmony_ci 135253a5a1b3Sopenharmony_ciconst char* pa_context_get_server(const pa_context *c) { 135353a5a1b3Sopenharmony_ci pa_assert(c); 135453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 135553a5a1b3Sopenharmony_ci 135653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 135753a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->server, PA_ERR_NOENTITY); 135853a5a1b3Sopenharmony_ci 135953a5a1b3Sopenharmony_ci if (*c->server == '{') { 136053a5a1b3Sopenharmony_ci char *e = strchr(c->server+1, '}'); 136153a5a1b3Sopenharmony_ci return e ? e+1 : c->server; 136253a5a1b3Sopenharmony_ci } 136353a5a1b3Sopenharmony_ci 136453a5a1b3Sopenharmony_ci return c->server; 136553a5a1b3Sopenharmony_ci} 136653a5a1b3Sopenharmony_ci 136753a5a1b3Sopenharmony_ciuint32_t pa_context_get_protocol_version(const pa_context *c) { 136853a5a1b3Sopenharmony_ci return PA_PROTOCOL_VERSION; 136953a5a1b3Sopenharmony_ci} 137053a5a1b3Sopenharmony_ci 137153a5a1b3Sopenharmony_ciuint32_t pa_context_get_server_protocol_version(const pa_context *c) { 137253a5a1b3Sopenharmony_ci pa_assert(c); 137353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 137453a5a1b3Sopenharmony_ci 137553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX); 137653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX); 137753a5a1b3Sopenharmony_ci 137853a5a1b3Sopenharmony_ci return c->version; 137953a5a1b3Sopenharmony_ci} 138053a5a1b3Sopenharmony_ci 138153a5a1b3Sopenharmony_cipa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { 138253a5a1b3Sopenharmony_ci pa_tagstruct *t; 138353a5a1b3Sopenharmony_ci 138453a5a1b3Sopenharmony_ci pa_assert(c); 138553a5a1b3Sopenharmony_ci pa_assert(tag); 138653a5a1b3Sopenharmony_ci 138753a5a1b3Sopenharmony_ci t = pa_tagstruct_new(); 138853a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, command); 138953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, *tag = c->ctag++); 139053a5a1b3Sopenharmony_ci 139153a5a1b3Sopenharmony_ci return t; 139253a5a1b3Sopenharmony_ci} 139353a5a1b3Sopenharmony_ci 139453a5a1b3Sopenharmony_ciuint32_t pa_context_get_index(const pa_context *c) { 139553a5a1b3Sopenharmony_ci pa_assert(c); 139653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 139753a5a1b3Sopenharmony_ci 139853a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, PA_INVALID_INDEX); 139953a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); 140053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX); 140153a5a1b3Sopenharmony_ci 140253a5a1b3Sopenharmony_ci return c->client_index; 140353a5a1b3Sopenharmony_ci} 140453a5a1b3Sopenharmony_ci 140553a5a1b3Sopenharmony_cipa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, const pa_proplist *p, pa_context_success_cb_t cb, void *userdata) { 140653a5a1b3Sopenharmony_ci pa_operation *o; 140753a5a1b3Sopenharmony_ci pa_tagstruct *t; 140853a5a1b3Sopenharmony_ci uint32_t tag; 140953a5a1b3Sopenharmony_ci 141053a5a1b3Sopenharmony_ci pa_assert(c); 141153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 141253a5a1b3Sopenharmony_ci 141353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 141453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID); 141553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 141653a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED); 141753a5a1b3Sopenharmony_ci 141853a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 141953a5a1b3Sopenharmony_ci 142053a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag); 142153a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t, (uint32_t) mode); 142253a5a1b3Sopenharmony_ci pa_tagstruct_put_proplist(t, p); 142353a5a1b3Sopenharmony_ci 142453a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 142553a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 142653a5a1b3Sopenharmony_ci 142753a5a1b3Sopenharmony_ci /* Please note that we don't update c->proplist here, because we 142853a5a1b3Sopenharmony_ci * don't export that field */ 142953a5a1b3Sopenharmony_ci 143053a5a1b3Sopenharmony_ci return o; 143153a5a1b3Sopenharmony_ci} 143253a5a1b3Sopenharmony_ci 143353a5a1b3Sopenharmony_cipa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) { 143453a5a1b3Sopenharmony_ci pa_operation *o; 143553a5a1b3Sopenharmony_ci pa_tagstruct *t; 143653a5a1b3Sopenharmony_ci uint32_t tag; 143753a5a1b3Sopenharmony_ci const char * const *k; 143853a5a1b3Sopenharmony_ci 143953a5a1b3Sopenharmony_ci pa_assert(c); 144053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 144153a5a1b3Sopenharmony_ci 144253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, !pa_detect_fork(), PA_ERR_FORKED); 144353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID); 144453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); 144553a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED); 144653a5a1b3Sopenharmony_ci 144753a5a1b3Sopenharmony_ci o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); 144853a5a1b3Sopenharmony_ci 144953a5a1b3Sopenharmony_ci t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag); 145053a5a1b3Sopenharmony_ci 145153a5a1b3Sopenharmony_ci for (k = keys; *k; k++) 145253a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, *k); 145353a5a1b3Sopenharmony_ci 145453a5a1b3Sopenharmony_ci pa_tagstruct_puts(t, NULL); 145553a5a1b3Sopenharmony_ci 145653a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t); 145753a5a1b3Sopenharmony_ci pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); 145853a5a1b3Sopenharmony_ci 145953a5a1b3Sopenharmony_ci /* Please note that we don't update c->proplist here, because we 146053a5a1b3Sopenharmony_ci * don't export that field */ 146153a5a1b3Sopenharmony_ci 146253a5a1b3Sopenharmony_ci return o; 146353a5a1b3Sopenharmony_ci} 146453a5a1b3Sopenharmony_ci 146553a5a1b3Sopenharmony_civoid pa_command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 146653a5a1b3Sopenharmony_ci pa_context *c = userdata; 146753a5a1b3Sopenharmony_ci uint32_t idx; 146853a5a1b3Sopenharmony_ci const char *name; 146953a5a1b3Sopenharmony_ci 147053a5a1b3Sopenharmony_ci pa_assert(pd); 147153a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_EXTENSION); 147253a5a1b3Sopenharmony_ci pa_assert(t); 147353a5a1b3Sopenharmony_ci pa_assert(c); 147453a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 147553a5a1b3Sopenharmony_ci 147653a5a1b3Sopenharmony_ci pa_context_ref(c); 147753a5a1b3Sopenharmony_ci 147853a5a1b3Sopenharmony_ci if (c->version < 15) { 147953a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 148053a5a1b3Sopenharmony_ci goto finish; 148153a5a1b3Sopenharmony_ci } 148253a5a1b3Sopenharmony_ci 148353a5a1b3Sopenharmony_ci if (pa_tagstruct_getu32(t, &idx) < 0 || 148453a5a1b3Sopenharmony_ci pa_tagstruct_gets(t, &name) < 0) { 148553a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 148653a5a1b3Sopenharmony_ci goto finish; 148753a5a1b3Sopenharmony_ci } 148853a5a1b3Sopenharmony_ci 148953a5a1b3Sopenharmony_ci if (pa_streq(name, "module-device-manager")) 149053a5a1b3Sopenharmony_ci pa_ext_device_manager_command(c, tag, t); 149153a5a1b3Sopenharmony_ci else if (pa_streq(name, "module-device-restore")) 149253a5a1b3Sopenharmony_ci pa_ext_device_restore_command(c, tag, t); 149353a5a1b3Sopenharmony_ci else if (pa_streq(name, "module-stream-restore")) 149453a5a1b3Sopenharmony_ci pa_ext_stream_restore_command(c, tag, t); 149553a5a1b3Sopenharmony_ci else 149653a5a1b3Sopenharmony_ci pa_log(_("Received message for unknown extension '%s'"), name); 149753a5a1b3Sopenharmony_ci 149853a5a1b3Sopenharmony_cifinish: 149953a5a1b3Sopenharmony_ci pa_context_unref(c); 150053a5a1b3Sopenharmony_ci} 150153a5a1b3Sopenharmony_ci 150253a5a1b3Sopenharmony_cistatic void pa_command_enable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 150353a5a1b3Sopenharmony_ci pa_context *c = userdata; 150453a5a1b3Sopenharmony_ci 150553a5a1b3Sopenharmony_ci#ifdef HAVE_CREDS 150653a5a1b3Sopenharmony_ci pa_cmsg_ancil_data *ancil = NULL; 150753a5a1b3Sopenharmony_ci 150853a5a1b3Sopenharmony_ci pa_assert(pd); 150953a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_ENABLE_SRBCHANNEL); 151053a5a1b3Sopenharmony_ci pa_assert(t); 151153a5a1b3Sopenharmony_ci pa_assert(c); 151253a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 151353a5a1b3Sopenharmony_ci 151453a5a1b3Sopenharmony_ci ancil = pa_pdispatch_take_ancil_data(pd); 151553a5a1b3Sopenharmony_ci if (!ancil) 151653a5a1b3Sopenharmony_ci goto fail; 151753a5a1b3Sopenharmony_ci 151853a5a1b3Sopenharmony_ci /* Currently only one srb channel is supported, might change in future versions */ 151953a5a1b3Sopenharmony_ci if (c->srb_template.readfd != -1) 152053a5a1b3Sopenharmony_ci goto fail; 152153a5a1b3Sopenharmony_ci 152253a5a1b3Sopenharmony_ci if (ancil->nfd != 2 || ancil->fds[0] == -1 || ancil->fds[1] == -1) 152353a5a1b3Sopenharmony_ci goto fail; 152453a5a1b3Sopenharmony_ci 152553a5a1b3Sopenharmony_ci pa_context_ref(c); 152653a5a1b3Sopenharmony_ci 152753a5a1b3Sopenharmony_ci c->srb_template.readfd = ancil->fds[0]; 152853a5a1b3Sopenharmony_ci c->srb_template.writefd = ancil->fds[1]; 152953a5a1b3Sopenharmony_ci c->srb_setup_tag = tag; 153053a5a1b3Sopenharmony_ci 153153a5a1b3Sopenharmony_ci pa_context_unref(c); 153253a5a1b3Sopenharmony_ci 153353a5a1b3Sopenharmony_ci ancil->close_fds_on_cleanup = false; 153453a5a1b3Sopenharmony_ci return; 153553a5a1b3Sopenharmony_ci 153653a5a1b3Sopenharmony_cifail: 153753a5a1b3Sopenharmony_ci if (ancil) 153853a5a1b3Sopenharmony_ci pa_cmsg_ancil_data_close_fds(ancil); 153953a5a1b3Sopenharmony_ci 154053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 154153a5a1b3Sopenharmony_ci return; 154253a5a1b3Sopenharmony_ci#else 154353a5a1b3Sopenharmony_ci pa_assert(c); 154453a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 154553a5a1b3Sopenharmony_ci#endif 154653a5a1b3Sopenharmony_ci} 154753a5a1b3Sopenharmony_ci 154853a5a1b3Sopenharmony_cistatic void pa_command_disable_srbchannel(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 154953a5a1b3Sopenharmony_ci pa_context *c = userdata; 155053a5a1b3Sopenharmony_ci pa_tagstruct *t2; 155153a5a1b3Sopenharmony_ci 155253a5a1b3Sopenharmony_ci pa_assert(pd); 155353a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_DISABLE_SRBCHANNEL); 155453a5a1b3Sopenharmony_ci pa_assert(t); 155553a5a1b3Sopenharmony_ci pa_assert(c); 155653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 155753a5a1b3Sopenharmony_ci 155853a5a1b3Sopenharmony_ci pa_pstream_set_srbchannel(c->pstream, NULL); 155953a5a1b3Sopenharmony_ci 156053a5a1b3Sopenharmony_ci c->srb_template.readfd = -1; 156153a5a1b3Sopenharmony_ci c->srb_template.writefd = -1; 156253a5a1b3Sopenharmony_ci if (c->srb_template.memblock) { 156353a5a1b3Sopenharmony_ci pa_memblock_unref(c->srb_template.memblock); 156453a5a1b3Sopenharmony_ci c->srb_template.memblock = NULL; 156553a5a1b3Sopenharmony_ci } 156653a5a1b3Sopenharmony_ci 156753a5a1b3Sopenharmony_ci /* Send disable command back again */ 156853a5a1b3Sopenharmony_ci t2 = pa_tagstruct_new(); 156953a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t2, PA_COMMAND_DISABLE_SRBCHANNEL); 157053a5a1b3Sopenharmony_ci pa_tagstruct_putu32(t2, tag); 157153a5a1b3Sopenharmony_ci pa_pstream_send_tagstruct(c->pstream, t2); 157253a5a1b3Sopenharmony_ci} 157353a5a1b3Sopenharmony_ci 157453a5a1b3Sopenharmony_cistatic void pa_command_register_memfd_shmid(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 157553a5a1b3Sopenharmony_ci pa_context *c = userdata; 157653a5a1b3Sopenharmony_ci 157753a5a1b3Sopenharmony_ci pa_assert(pd); 157853a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_REGISTER_MEMFD_SHMID); 157953a5a1b3Sopenharmony_ci pa_assert(t); 158053a5a1b3Sopenharmony_ci pa_assert(c); 158153a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 158253a5a1b3Sopenharmony_ci 158353a5a1b3Sopenharmony_ci if (pa_common_command_register_memfd_shmid(c->pstream, pd, c->version, command, t)) 158453a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 158553a5a1b3Sopenharmony_ci} 158653a5a1b3Sopenharmony_ci 158753a5a1b3Sopenharmony_civoid pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { 158853a5a1b3Sopenharmony_ci pa_context *c = userdata; 158953a5a1b3Sopenharmony_ci pa_proplist *pl = NULL; 159053a5a1b3Sopenharmony_ci const char *event; 159153a5a1b3Sopenharmony_ci 159253a5a1b3Sopenharmony_ci pa_assert(pd); 159353a5a1b3Sopenharmony_ci pa_assert(command == PA_COMMAND_CLIENT_EVENT); 159453a5a1b3Sopenharmony_ci pa_assert(t); 159553a5a1b3Sopenharmony_ci pa_assert(c); 159653a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 159753a5a1b3Sopenharmony_ci 159853a5a1b3Sopenharmony_ci pa_context_ref(c); 159953a5a1b3Sopenharmony_ci 160053a5a1b3Sopenharmony_ci if (c->version < 15) { 160153a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 160253a5a1b3Sopenharmony_ci goto finish; 160353a5a1b3Sopenharmony_ci } 160453a5a1b3Sopenharmony_ci 160553a5a1b3Sopenharmony_ci pl = pa_proplist_new(); 160653a5a1b3Sopenharmony_ci 160753a5a1b3Sopenharmony_ci if (pa_tagstruct_gets(t, &event) < 0 || 160853a5a1b3Sopenharmony_ci pa_tagstruct_get_proplist(t, pl) < 0 || 160953a5a1b3Sopenharmony_ci !pa_tagstruct_eof(t) || !event) { 161053a5a1b3Sopenharmony_ci pa_context_fail(c, PA_ERR_PROTOCOL); 161153a5a1b3Sopenharmony_ci goto finish; 161253a5a1b3Sopenharmony_ci } 161353a5a1b3Sopenharmony_ci 161453a5a1b3Sopenharmony_ci if (c->event_callback) 161553a5a1b3Sopenharmony_ci c->event_callback(c, event, pl, c->event_userdata); 161653a5a1b3Sopenharmony_ci 161753a5a1b3Sopenharmony_cifinish: 161853a5a1b3Sopenharmony_ci pa_context_unref(c); 161953a5a1b3Sopenharmony_ci 162053a5a1b3Sopenharmony_ci if (pl) 162153a5a1b3Sopenharmony_ci pa_proplist_free(pl); 162253a5a1b3Sopenharmony_ci} 162353a5a1b3Sopenharmony_ci 162453a5a1b3Sopenharmony_cipa_time_event* pa_context_rttime_new(const pa_context *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) { 162553a5a1b3Sopenharmony_ci struct timeval tv; 162653a5a1b3Sopenharmony_ci 162753a5a1b3Sopenharmony_ci pa_assert(c); 162853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 162953a5a1b3Sopenharmony_ci pa_assert(c->mainloop); 163053a5a1b3Sopenharmony_ci 163153a5a1b3Sopenharmony_ci if (usec == PA_USEC_INVALID) 163253a5a1b3Sopenharmony_ci return c->mainloop->time_new(c->mainloop, NULL, cb, userdata); 163353a5a1b3Sopenharmony_ci 163453a5a1b3Sopenharmony_ci pa_timeval_rtstore(&tv, usec, c->use_rtclock); 163553a5a1b3Sopenharmony_ci 163653a5a1b3Sopenharmony_ci return c->mainloop->time_new(c->mainloop, &tv, cb, userdata); 163753a5a1b3Sopenharmony_ci} 163853a5a1b3Sopenharmony_ci 163953a5a1b3Sopenharmony_civoid pa_context_rttime_restart(const pa_context *c, pa_time_event *e, pa_usec_t usec) { 164053a5a1b3Sopenharmony_ci struct timeval tv; 164153a5a1b3Sopenharmony_ci 164253a5a1b3Sopenharmony_ci pa_assert(c); 164353a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 164453a5a1b3Sopenharmony_ci pa_assert(c->mainloop); 164553a5a1b3Sopenharmony_ci 164653a5a1b3Sopenharmony_ci if (usec == PA_USEC_INVALID) 164753a5a1b3Sopenharmony_ci c->mainloop->time_restart(e, NULL); 164853a5a1b3Sopenharmony_ci else { 164953a5a1b3Sopenharmony_ci pa_timeval_rtstore(&tv, usec, c->use_rtclock); 165053a5a1b3Sopenharmony_ci c->mainloop->time_restart(e, &tv); 165153a5a1b3Sopenharmony_ci } 165253a5a1b3Sopenharmony_ci} 165353a5a1b3Sopenharmony_ci 165453a5a1b3Sopenharmony_cisize_t pa_context_get_tile_size(const pa_context *c, const pa_sample_spec *ss) { 165553a5a1b3Sopenharmony_ci size_t fs, mbs; 165653a5a1b3Sopenharmony_ci 165753a5a1b3Sopenharmony_ci pa_assert(c); 165853a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 165953a5a1b3Sopenharmony_ci 166053a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, !pa_detect_fork(), PA_ERR_FORKED, (size_t) -1); 166153a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY_RETURN_ANY(c, !ss || pa_sample_spec_valid(ss), PA_ERR_INVALID, (size_t) -1); 166253a5a1b3Sopenharmony_ci 166353a5a1b3Sopenharmony_ci fs = ss ? pa_frame_size(ss) : 1; 166453a5a1b3Sopenharmony_ci mbs = PA_ROUND_DOWN(pa_mempool_block_size_max(c->mempool), fs); 166553a5a1b3Sopenharmony_ci return PA_MAX(mbs, fs); 166653a5a1b3Sopenharmony_ci} 166753a5a1b3Sopenharmony_ci 166853a5a1b3Sopenharmony_ciint pa_context_load_cookie_from_file(pa_context *c, const char *cookie_file_path) { 166953a5a1b3Sopenharmony_ci pa_assert(c); 167053a5a1b3Sopenharmony_ci pa_assert(PA_REFCNT_VALUE(c) >= 1); 167153a5a1b3Sopenharmony_ci 167253a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !pa_detect_fork(), PA_ERR_FORKED); 167353a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); 167453a5a1b3Sopenharmony_ci PA_CHECK_VALIDITY(c, !cookie_file_path || *cookie_file_path, PA_ERR_INVALID); 167553a5a1b3Sopenharmony_ci 167653a5a1b3Sopenharmony_ci pa_client_conf_set_cookie_file_from_application(c->conf, cookie_file_path); 167753a5a1b3Sopenharmony_ci 167853a5a1b3Sopenharmony_ci return 0; 167953a5a1b3Sopenharmony_ci} 1680