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