153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2004-2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
953a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1053a5a1b3Sopenharmony_ci  or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1853a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#ifndef LOG_TAG
2653a5a1b3Sopenharmony_ci#define LOG_TAG "Core"
2753a5a1b3Sopenharmony_ci#endif
2853a5a1b3Sopenharmony_ci
2953a5a1b3Sopenharmony_ci#include <stdlib.h>
3053a5a1b3Sopenharmony_ci#include <stdio.h>
3153a5a1b3Sopenharmony_ci#include <signal.h>
3253a5a1b3Sopenharmony_ci
3353a5a1b3Sopenharmony_ci#include <pulse/rtclock.h>
3453a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
3553a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3653a5a1b3Sopenharmony_ci
3753a5a1b3Sopenharmony_ci#include <pulsecore/module.h>
3853a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h>
3953a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
4053a5a1b3Sopenharmony_ci#include <pulsecore/message-handler.h>
4153a5a1b3Sopenharmony_ci#include <pulsecore/core-scache.h>
4253a5a1b3Sopenharmony_ci#include <pulsecore/core-subscribe.h>
4353a5a1b3Sopenharmony_ci#include <pulsecore/random.h>
4453a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
4553a5a1b3Sopenharmony_ci#include <pulsecore/macro.h>
4653a5a1b3Sopenharmony_ci#include <pulsecore/strbuf.h>
4753a5a1b3Sopenharmony_ci
4853a5a1b3Sopenharmony_ci#include "core.h"
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_ciPA_DEFINE_PUBLIC_CLASS(pa_core, pa_msgobject);
5153a5a1b3Sopenharmony_ci
5253a5a1b3Sopenharmony_cistatic int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
5353a5a1b3Sopenharmony_ci    pa_core *c = PA_CORE(o);
5453a5a1b3Sopenharmony_ci
5553a5a1b3Sopenharmony_ci    pa_core_assert_ref(c);
5653a5a1b3Sopenharmony_ci
5753a5a1b3Sopenharmony_ci    switch (code) {
5853a5a1b3Sopenharmony_ci
5953a5a1b3Sopenharmony_ci        case PA_CORE_MESSAGE_UNLOAD_MODULE:
6053a5a1b3Sopenharmony_ci            pa_module_unload(userdata, true);
6153a5a1b3Sopenharmony_ci            return 0;
6253a5a1b3Sopenharmony_ci
6353a5a1b3Sopenharmony_ci        default:
6453a5a1b3Sopenharmony_ci            return -1;
6553a5a1b3Sopenharmony_ci    }
6653a5a1b3Sopenharmony_ci}
6753a5a1b3Sopenharmony_ci
6853a5a1b3Sopenharmony_cistatic void core_free(pa_object *o);
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_ci/* Returns a list of handlers. */
7153a5a1b3Sopenharmony_cistatic char *message_handler_list(pa_core *c) {
7253a5a1b3Sopenharmony_ci    pa_json_encoder *encoder;
7353a5a1b3Sopenharmony_ci    void *state = NULL;
7453a5a1b3Sopenharmony_ci    struct pa_message_handler *handler;
7553a5a1b3Sopenharmony_ci
7653a5a1b3Sopenharmony_ci    encoder = pa_json_encoder_new();
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_ci    pa_json_encoder_begin_element_array(encoder);
7953a5a1b3Sopenharmony_ci    PA_HASHMAP_FOREACH(handler, c->message_handlers, state) {
8053a5a1b3Sopenharmony_ci        pa_json_encoder_begin_element_object(encoder);
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ci        pa_json_encoder_add_member_string(encoder, "name", handler->object_path);
8353a5a1b3Sopenharmony_ci        pa_json_encoder_add_member_string(encoder, "description", handler->description);
8453a5a1b3Sopenharmony_ci
8553a5a1b3Sopenharmony_ci        pa_json_encoder_end_object(encoder);
8653a5a1b3Sopenharmony_ci    }
8753a5a1b3Sopenharmony_ci    pa_json_encoder_end_array(encoder);
8853a5a1b3Sopenharmony_ci
8953a5a1b3Sopenharmony_ci    return pa_json_encoder_to_string_free(encoder);
9053a5a1b3Sopenharmony_ci}
9153a5a1b3Sopenharmony_ci
9253a5a1b3Sopenharmony_cistatic int core_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) {
9353a5a1b3Sopenharmony_ci    pa_core *c = userdata;
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_ci    pa_assert(c);
9653a5a1b3Sopenharmony_ci    pa_assert(message);
9753a5a1b3Sopenharmony_ci    pa_assert(response);
9853a5a1b3Sopenharmony_ci    pa_assert(pa_safe_streq(object_path, "/core"));
9953a5a1b3Sopenharmony_ci
10053a5a1b3Sopenharmony_ci    if (pa_streq(message, "list-handlers")) {
10153a5a1b3Sopenharmony_ci        *response = message_handler_list(c);
10253a5a1b3Sopenharmony_ci        return PA_OK;
10353a5a1b3Sopenharmony_ci    }
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    return -PA_ERR_NOTIMPLEMENTED;
10653a5a1b3Sopenharmony_ci}
10753a5a1b3Sopenharmony_ci
10853a5a1b3Sopenharmony_cipa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size) {
10953a5a1b3Sopenharmony_ci    pa_log_info("start pa_core_new, shared: %d, enable_memfd: %d", shared, enable_memfd);
11053a5a1b3Sopenharmony_ci    pa_core* c;
11153a5a1b3Sopenharmony_ci    pa_mempool *pool;
11253a5a1b3Sopenharmony_ci    pa_mem_type_t type;
11353a5a1b3Sopenharmony_ci    int j;
11453a5a1b3Sopenharmony_ci
11553a5a1b3Sopenharmony_ci    pa_assert(m);
11653a5a1b3Sopenharmony_ci
11753a5a1b3Sopenharmony_ci    if (shared) {
11853a5a1b3Sopenharmony_ci        type = (enable_memfd) ? PA_MEM_TYPE_SHARED_MEMFD : PA_MEM_TYPE_SHARED_POSIX;
11953a5a1b3Sopenharmony_ci        if (!(pool = pa_mempool_new(type, shm_size, false))) {
12053a5a1b3Sopenharmony_ci            pa_log_warn("Failed to allocate %s memory pool. Falling back to a normal memory pool.",
12153a5a1b3Sopenharmony_ci                        pa_mem_type_to_string(type));
12253a5a1b3Sopenharmony_ci            shared = false;
12353a5a1b3Sopenharmony_ci        }
12453a5a1b3Sopenharmony_ci    }
12553a5a1b3Sopenharmony_ci
12653a5a1b3Sopenharmony_ci    if (!shared) {
12753a5a1b3Sopenharmony_ci        if (!(pool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, shm_size, false))) {
12853a5a1b3Sopenharmony_ci            pa_log_error("pa_mempool_new() failed.");
12953a5a1b3Sopenharmony_ci            return NULL;
13053a5a1b3Sopenharmony_ci        }
13153a5a1b3Sopenharmony_ci    }
13253a5a1b3Sopenharmony_ci
13353a5a1b3Sopenharmony_ci    c = pa_msgobject_new(pa_core);
13453a5a1b3Sopenharmony_ci    c->parent.parent.free = core_free;
13553a5a1b3Sopenharmony_ci    c->parent.process_msg = core_process_msg;
13653a5a1b3Sopenharmony_ci
13753a5a1b3Sopenharmony_ci    c->state = PA_CORE_STARTUP;
13853a5a1b3Sopenharmony_ci    c->mainloop = m;
13953a5a1b3Sopenharmony_ci
14053a5a1b3Sopenharmony_ci    c->clients = pa_idxset_new(NULL, NULL);
14153a5a1b3Sopenharmony_ci    c->cards = pa_idxset_new(NULL, NULL);
14253a5a1b3Sopenharmony_ci    c->sinks = pa_idxset_new(NULL, NULL);
14353a5a1b3Sopenharmony_ci    c->sources = pa_idxset_new(NULL, NULL);
14453a5a1b3Sopenharmony_ci    c->sink_inputs = pa_idxset_new(NULL, NULL);
14553a5a1b3Sopenharmony_ci    c->source_outputs = pa_idxset_new(NULL, NULL);
14653a5a1b3Sopenharmony_ci    c->modules = pa_idxset_new(NULL, NULL);
14753a5a1b3Sopenharmony_ci    c->scache = pa_idxset_new(NULL, NULL);
14853a5a1b3Sopenharmony_ci
14953a5a1b3Sopenharmony_ci    c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
15053a5a1b3Sopenharmony_ci    c->shared = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
15153a5a1b3Sopenharmony_ci    c->message_handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
15253a5a1b3Sopenharmony_ci
15353a5a1b3Sopenharmony_ci    pa_message_handler_register(c, "/core", "Core message handler", core_message_handler, (void *) c);
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    c->default_source = NULL;
15653a5a1b3Sopenharmony_ci    c->default_sink = NULL;
15753a5a1b3Sopenharmony_ci
15853a5a1b3Sopenharmony_ci    c->default_sample_spec.format = PA_SAMPLE_S16NE;
15953a5a1b3Sopenharmony_ci    c->default_sample_spec.rate = 44100;
16053a5a1b3Sopenharmony_ci    c->default_sample_spec.channels = 2;
16153a5a1b3Sopenharmony_ci    pa_channel_map_init_extend(&c->default_channel_map, c->default_sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
16253a5a1b3Sopenharmony_ci    c->default_n_fragments = 4;
16353a5a1b3Sopenharmony_ci    c->default_fragment_size_msec = 25;
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    c->deferred_volume_safety_margin_usec = 8000;
16653a5a1b3Sopenharmony_ci    c->deferred_volume_extra_delay_usec = 0;
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci    c->module_defer_unload_event = NULL;
16953a5a1b3Sopenharmony_ci    c->modules_pending_unload = pa_hashmap_new(NULL, NULL);
17053a5a1b3Sopenharmony_ci
17153a5a1b3Sopenharmony_ci    c->subscription_defer_event = NULL;
17253a5a1b3Sopenharmony_ci    PA_LLIST_HEAD_INIT(pa_subscription, c->subscriptions);
17353a5a1b3Sopenharmony_ci    PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue);
17453a5a1b3Sopenharmony_ci    c->subscription_event_last = NULL;
17553a5a1b3Sopenharmony_ci
17653a5a1b3Sopenharmony_ci    c->mempool = pool;
17753a5a1b3Sopenharmony_ci    c->shm_size = shm_size;
17853a5a1b3Sopenharmony_ci    pa_silence_cache_init(&c->silence_cache);
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci    c->exit_event = NULL;
18153a5a1b3Sopenharmony_ci    c->scache_auto_unload_event = NULL;
18253a5a1b3Sopenharmony_ci
18353a5a1b3Sopenharmony_ci    c->exit_idle_time = -1;
18453a5a1b3Sopenharmony_ci    c->scache_idle_time = 20;
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_ci    c->flat_volumes = true;
18753a5a1b3Sopenharmony_ci    c->disallow_module_loading = false;
18853a5a1b3Sopenharmony_ci    c->disallow_exit = false;
18953a5a1b3Sopenharmony_ci    c->running_as_daemon = false;
19053a5a1b3Sopenharmony_ci    c->realtime_scheduling = false;
19153a5a1b3Sopenharmony_ci    c->realtime_priority = 5;
19253a5a1b3Sopenharmony_ci    c->disable_remixing = false;
19353a5a1b3Sopenharmony_ci    c->remixing_use_all_sink_channels = true;
19453a5a1b3Sopenharmony_ci    c->remixing_produce_lfe = false;
19553a5a1b3Sopenharmony_ci    c->remixing_consume_lfe = false;
19653a5a1b3Sopenharmony_ci    c->lfe_crossover_freq = 0;
19753a5a1b3Sopenharmony_ci    c->deferred_volume = true;
19853a5a1b3Sopenharmony_ci    c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 1;
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci    for (j = 0; j < PA_CORE_HOOK_MAX; j++)
20153a5a1b3Sopenharmony_ci        pa_hook_init(&c->hooks[j], c);
20253a5a1b3Sopenharmony_ci
20353a5a1b3Sopenharmony_ci    pa_random(&c->cookie, sizeof(c->cookie));
20453a5a1b3Sopenharmony_ci
20553a5a1b3Sopenharmony_ci#ifdef SIGPIPE
20653a5a1b3Sopenharmony_ci    pa_check_signal_is_blocked(SIGPIPE);
20753a5a1b3Sopenharmony_ci#endif
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_ci    return c;
21053a5a1b3Sopenharmony_ci}
21153a5a1b3Sopenharmony_ci
21253a5a1b3Sopenharmony_cistatic void core_free(pa_object *o) {
21353a5a1b3Sopenharmony_ci    pa_core *c = PA_CORE(o);
21453a5a1b3Sopenharmony_ci    int j;
21553a5a1b3Sopenharmony_ci    pa_assert(c);
21653a5a1b3Sopenharmony_ci
21753a5a1b3Sopenharmony_ci    c->state = PA_CORE_SHUTDOWN;
21853a5a1b3Sopenharmony_ci
21953a5a1b3Sopenharmony_ci    /* Note: All modules and samples in the cache should be unloaded before
22053a5a1b3Sopenharmony_ci     * we get here */
22153a5a1b3Sopenharmony_ci
22253a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->scache));
22353a5a1b3Sopenharmony_ci    pa_idxset_free(c->scache, NULL);
22453a5a1b3Sopenharmony_ci
22553a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->modules));
22653a5a1b3Sopenharmony_ci    pa_idxset_free(c->modules, NULL);
22753a5a1b3Sopenharmony_ci
22853a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->clients));
22953a5a1b3Sopenharmony_ci    pa_idxset_free(c->clients, NULL);
23053a5a1b3Sopenharmony_ci
23153a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->cards));
23253a5a1b3Sopenharmony_ci    pa_idxset_free(c->cards, NULL);
23353a5a1b3Sopenharmony_ci
23453a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->sinks));
23553a5a1b3Sopenharmony_ci    pa_idxset_free(c->sinks, NULL);
23653a5a1b3Sopenharmony_ci
23753a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->sources));
23853a5a1b3Sopenharmony_ci    pa_idxset_free(c->sources, NULL);
23953a5a1b3Sopenharmony_ci
24053a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->source_outputs));
24153a5a1b3Sopenharmony_ci    pa_idxset_free(c->source_outputs, NULL);
24253a5a1b3Sopenharmony_ci
24353a5a1b3Sopenharmony_ci    pa_assert(pa_idxset_isempty(c->sink_inputs));
24453a5a1b3Sopenharmony_ci    pa_idxset_free(c->sink_inputs, NULL);
24553a5a1b3Sopenharmony_ci
24653a5a1b3Sopenharmony_ci    pa_assert(pa_hashmap_isempty(c->namereg));
24753a5a1b3Sopenharmony_ci    pa_hashmap_free(c->namereg);
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_ci    pa_assert(pa_hashmap_isempty(c->shared));
25053a5a1b3Sopenharmony_ci    pa_hashmap_free(c->shared);
25153a5a1b3Sopenharmony_ci
25253a5a1b3Sopenharmony_ci    pa_message_handler_unregister(c, "/core");
25353a5a1b3Sopenharmony_ci
25453a5a1b3Sopenharmony_ci    pa_assert(pa_hashmap_isempty(c->message_handlers));
25553a5a1b3Sopenharmony_ci    pa_hashmap_free(c->message_handlers);
25653a5a1b3Sopenharmony_ci
25753a5a1b3Sopenharmony_ci    pa_assert(pa_hashmap_isempty(c->modules_pending_unload));
25853a5a1b3Sopenharmony_ci    pa_hashmap_free(c->modules_pending_unload);
25953a5a1b3Sopenharmony_ci
26053a5a1b3Sopenharmony_ci    pa_subscription_free_all(c);
26153a5a1b3Sopenharmony_ci
26253a5a1b3Sopenharmony_ci    if (c->exit_event)
26353a5a1b3Sopenharmony_ci        c->mainloop->time_free(c->exit_event);
26453a5a1b3Sopenharmony_ci
26553a5a1b3Sopenharmony_ci    pa_assert(!c->default_source);
26653a5a1b3Sopenharmony_ci    pa_assert(!c->default_sink);
26753a5a1b3Sopenharmony_ci    pa_xfree(c->configured_default_source);
26853a5a1b3Sopenharmony_ci    pa_xfree(c->configured_default_sink);
26953a5a1b3Sopenharmony_ci
27053a5a1b3Sopenharmony_ci    pa_silence_cache_done(&c->silence_cache);
27153a5a1b3Sopenharmony_ci    pa_mempool_unref(c->mempool);
27253a5a1b3Sopenharmony_ci
27353a5a1b3Sopenharmony_ci    for (j = 0; j < PA_CORE_HOOK_MAX; j++)
27453a5a1b3Sopenharmony_ci        pa_hook_done(&c->hooks[j]);
27553a5a1b3Sopenharmony_ci
27653a5a1b3Sopenharmony_ci    pa_xfree(c);
27753a5a1b3Sopenharmony_ci}
27853a5a1b3Sopenharmony_ci
27953a5a1b3Sopenharmony_civoid pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
28053a5a1b3Sopenharmony_ci    char *old_sink;
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci    pa_assert(core);
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci    old_sink = pa_xstrdup(core->configured_default_sink);
28553a5a1b3Sopenharmony_ci
28653a5a1b3Sopenharmony_ci    if (pa_safe_streq(sink, old_sink))
28753a5a1b3Sopenharmony_ci        goto finish;
28853a5a1b3Sopenharmony_ci
28953a5a1b3Sopenharmony_ci    pa_xfree(core->configured_default_sink);
29053a5a1b3Sopenharmony_ci    core->configured_default_sink = pa_xstrdup(sink);
29153a5a1b3Sopenharmony_ci    pa_log_info("configured_default_sink: %s -> %s",
29253a5a1b3Sopenharmony_ci                old_sink ? old_sink : "(unset)", sink ? sink : "(unset)");
29353a5a1b3Sopenharmony_ci    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
29453a5a1b3Sopenharmony_ci
29553a5a1b3Sopenharmony_ci    pa_core_update_default_sink(core);
29653a5a1b3Sopenharmony_ci
29753a5a1b3Sopenharmony_cifinish:
29853a5a1b3Sopenharmony_ci    pa_xfree(old_sink);
29953a5a1b3Sopenharmony_ci}
30053a5a1b3Sopenharmony_ci
30153a5a1b3Sopenharmony_civoid pa_core_set_configured_default_source(pa_core *core, const char *source) {
30253a5a1b3Sopenharmony_ci    char *old_source;
30353a5a1b3Sopenharmony_ci
30453a5a1b3Sopenharmony_ci    pa_assert(core);
30553a5a1b3Sopenharmony_ci
30653a5a1b3Sopenharmony_ci    old_source = pa_xstrdup(core->configured_default_source);
30753a5a1b3Sopenharmony_ci
30853a5a1b3Sopenharmony_ci    if (pa_safe_streq(source, old_source))
30953a5a1b3Sopenharmony_ci        goto finish;
31053a5a1b3Sopenharmony_ci
31153a5a1b3Sopenharmony_ci    pa_xfree(core->configured_default_source);
31253a5a1b3Sopenharmony_ci    core->configured_default_source = pa_xstrdup(source);
31353a5a1b3Sopenharmony_ci    pa_log_info("configured_default_source: %s -> %s",
31453a5a1b3Sopenharmony_ci                old_source ? old_source : "(unset)", source ? source : "(unset)");
31553a5a1b3Sopenharmony_ci    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
31653a5a1b3Sopenharmony_ci
31753a5a1b3Sopenharmony_ci    pa_core_update_default_source(core);
31853a5a1b3Sopenharmony_ci
31953a5a1b3Sopenharmony_cifinish:
32053a5a1b3Sopenharmony_ci    pa_xfree(old_source);
32153a5a1b3Sopenharmony_ci}
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci/* a  < b  ->  return -1
32453a5a1b3Sopenharmony_ci * a == b  ->  return  0
32553a5a1b3Sopenharmony_ci * a  > b  ->  return  1 */
32653a5a1b3Sopenharmony_cistatic int compare_sinks(pa_sink *a, pa_sink *b) {
32753a5a1b3Sopenharmony_ci    pa_core *core;
32853a5a1b3Sopenharmony_ci
32953a5a1b3Sopenharmony_ci    core = a->core;
33053a5a1b3Sopenharmony_ci
33153a5a1b3Sopenharmony_ci    /* Available sinks always beat unavailable sinks. */
33253a5a1b3Sopenharmony_ci    if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
33353a5a1b3Sopenharmony_ci            && (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
33453a5a1b3Sopenharmony_ci        return -1;
33553a5a1b3Sopenharmony_ci    if (b->active_port && b->active_port->available == PA_AVAILABLE_NO
33653a5a1b3Sopenharmony_ci            && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
33753a5a1b3Sopenharmony_ci        return 1;
33853a5a1b3Sopenharmony_ci
33953a5a1b3Sopenharmony_ci    /* The configured default sink is preferred over any other sink. */
34053a5a1b3Sopenharmony_ci    if (pa_safe_streq(b->name, core->configured_default_sink))
34153a5a1b3Sopenharmony_ci        return -1;
34253a5a1b3Sopenharmony_ci    if (pa_safe_streq(a->name, core->configured_default_sink))
34353a5a1b3Sopenharmony_ci        return 1;
34453a5a1b3Sopenharmony_ci
34553a5a1b3Sopenharmony_ci    if (a->priority < b->priority)
34653a5a1b3Sopenharmony_ci        return -1;
34753a5a1b3Sopenharmony_ci    if (a->priority > b->priority)
34853a5a1b3Sopenharmony_ci        return 1;
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci    /* It's hard to find any difference between these sinks, but maybe one of
35153a5a1b3Sopenharmony_ci     * them is already the default sink? If so, it's best to keep it as the
35253a5a1b3Sopenharmony_ci     * default to avoid changing the routing for no good reason. */
35353a5a1b3Sopenharmony_ci    if (b == core->default_sink)
35453a5a1b3Sopenharmony_ci        return -1;
35553a5a1b3Sopenharmony_ci    if (a == core->default_sink)
35653a5a1b3Sopenharmony_ci        return 1;
35753a5a1b3Sopenharmony_ci
35853a5a1b3Sopenharmony_ci    return 0;
35953a5a1b3Sopenharmony_ci}
36053a5a1b3Sopenharmony_ci
36153a5a1b3Sopenharmony_civoid pa_core_update_default_sink(pa_core *core) {
36253a5a1b3Sopenharmony_ci    pa_sink *best = NULL;
36353a5a1b3Sopenharmony_ci    pa_sink *sink;
36453a5a1b3Sopenharmony_ci    uint32_t idx;
36553a5a1b3Sopenharmony_ci    pa_sink *old_default_sink;
36653a5a1b3Sopenharmony_ci
36753a5a1b3Sopenharmony_ci    pa_assert(core);
36853a5a1b3Sopenharmony_ci
36953a5a1b3Sopenharmony_ci    PA_IDXSET_FOREACH(sink, core->sinks, idx) {
37053a5a1b3Sopenharmony_ci        if (!PA_SINK_IS_LINKED(sink->state))
37153a5a1b3Sopenharmony_ci            continue;
37253a5a1b3Sopenharmony_ci
37353a5a1b3Sopenharmony_ci        if (!best) {
37453a5a1b3Sopenharmony_ci            best = sink;
37553a5a1b3Sopenharmony_ci            continue;
37653a5a1b3Sopenharmony_ci        }
37753a5a1b3Sopenharmony_ci
37853a5a1b3Sopenharmony_ci        if (compare_sinks(sink, best) > 0)
37953a5a1b3Sopenharmony_ci            best = sink;
38053a5a1b3Sopenharmony_ci    }
38153a5a1b3Sopenharmony_ci
38253a5a1b3Sopenharmony_ci    old_default_sink = core->default_sink;
38353a5a1b3Sopenharmony_ci
38453a5a1b3Sopenharmony_ci    if (best == old_default_sink)
38553a5a1b3Sopenharmony_ci        return;
38653a5a1b3Sopenharmony_ci
38753a5a1b3Sopenharmony_ci    core->default_sink = best;
38853a5a1b3Sopenharmony_ci    pa_log_info("default_sink: %s -> %s",
38953a5a1b3Sopenharmony_ci                old_default_sink ? old_default_sink->name : "(unset)", best ? best->name : "(unset)");
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    /* If the default sink changed, it may be that the default source has to be
39253a5a1b3Sopenharmony_ci     * changed too, because monitor sources are prioritized partly based on the
39353a5a1b3Sopenharmony_ci     * priorities of the monitored sinks. */
39453a5a1b3Sopenharmony_ci    pa_core_update_default_source(core);
39553a5a1b3Sopenharmony_ci
39653a5a1b3Sopenharmony_ci    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
39753a5a1b3Sopenharmony_ci    pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED], core->default_sink);
39853a5a1b3Sopenharmony_ci
39953a5a1b3Sopenharmony_ci    /* try to move the streams from old_default_sink to the new default_sink conditionally */
40053a5a1b3Sopenharmony_ci    if (old_default_sink)
40153a5a1b3Sopenharmony_ci        pa_sink_move_streams_to_default_sink(core, old_default_sink, true);
40253a5a1b3Sopenharmony_ci}
40353a5a1b3Sopenharmony_ci
40453a5a1b3Sopenharmony_ci/* a  < b  ->  return -1
40553a5a1b3Sopenharmony_ci * a == b  ->  return  0
40653a5a1b3Sopenharmony_ci * a  > b  ->  return  1 */
40753a5a1b3Sopenharmony_cistatic int compare_sources(pa_source *a, pa_source *b) {
40853a5a1b3Sopenharmony_ci    pa_core *core;
40953a5a1b3Sopenharmony_ci
41053a5a1b3Sopenharmony_ci    core = a->core;
41153a5a1b3Sopenharmony_ci
41253a5a1b3Sopenharmony_ci    /* Available sources always beat unavailable sources. */
41353a5a1b3Sopenharmony_ci    if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
41453a5a1b3Sopenharmony_ci            && (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
41553a5a1b3Sopenharmony_ci        return -1;
41653a5a1b3Sopenharmony_ci    if (b->active_port && b->active_port->available == PA_AVAILABLE_NO
41753a5a1b3Sopenharmony_ci            && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
41853a5a1b3Sopenharmony_ci        return 1;
41953a5a1b3Sopenharmony_ci
42053a5a1b3Sopenharmony_ci    /* The configured default source is preferred over any other source. */
42153a5a1b3Sopenharmony_ci    if (pa_safe_streq(b->name, core->configured_default_source))
42253a5a1b3Sopenharmony_ci        return -1;
42353a5a1b3Sopenharmony_ci    if (pa_safe_streq(a->name, core->configured_default_source))
42453a5a1b3Sopenharmony_ci        return 1;
42553a5a1b3Sopenharmony_ci
42653a5a1b3Sopenharmony_ci    /* Monitor sources lose to non-monitor sources. */
42753a5a1b3Sopenharmony_ci    if (a->monitor_of && !b->monitor_of)
42853a5a1b3Sopenharmony_ci        return -1;
42953a5a1b3Sopenharmony_ci    if (!a->monitor_of && b->monitor_of)
43053a5a1b3Sopenharmony_ci        return 1;
43153a5a1b3Sopenharmony_ci
43253a5a1b3Sopenharmony_ci    if (a->priority < b->priority)
43353a5a1b3Sopenharmony_ci        return -1;
43453a5a1b3Sopenharmony_ci    if (a->priority > b->priority)
43553a5a1b3Sopenharmony_ci        return 1;
43653a5a1b3Sopenharmony_ci
43753a5a1b3Sopenharmony_ci    /* If the sources are monitors, we can compare the monitored sinks. */
43853a5a1b3Sopenharmony_ci    if (a->monitor_of)
43953a5a1b3Sopenharmony_ci        return compare_sinks(a->monitor_of, b->monitor_of);
44053a5a1b3Sopenharmony_ci
44153a5a1b3Sopenharmony_ci    /* It's hard to find any difference between these sources, but maybe one of
44253a5a1b3Sopenharmony_ci     * them is already the default source? If so, it's best to keep it as the
44353a5a1b3Sopenharmony_ci     * default to avoid changing the routing for no good reason. */
44453a5a1b3Sopenharmony_ci    if (b == core->default_source)
44553a5a1b3Sopenharmony_ci        return -1;
44653a5a1b3Sopenharmony_ci    if (a == core->default_source)
44753a5a1b3Sopenharmony_ci        return 1;
44853a5a1b3Sopenharmony_ci
44953a5a1b3Sopenharmony_ci    return 0;
45053a5a1b3Sopenharmony_ci}
45153a5a1b3Sopenharmony_ci
45253a5a1b3Sopenharmony_civoid pa_core_update_default_source(pa_core *core) {
45353a5a1b3Sopenharmony_ci    pa_source *best = NULL;
45453a5a1b3Sopenharmony_ci    pa_source *source;
45553a5a1b3Sopenharmony_ci    uint32_t idx;
45653a5a1b3Sopenharmony_ci    pa_source *old_default_source;
45753a5a1b3Sopenharmony_ci
45853a5a1b3Sopenharmony_ci    pa_assert(core);
45953a5a1b3Sopenharmony_ci
46053a5a1b3Sopenharmony_ci    PA_IDXSET_FOREACH(source, core->sources, idx) {
46153a5a1b3Sopenharmony_ci        if (!PA_SOURCE_IS_LINKED(source->state))
46253a5a1b3Sopenharmony_ci            continue;
46353a5a1b3Sopenharmony_ci
46453a5a1b3Sopenharmony_ci        if (!best) {
46553a5a1b3Sopenharmony_ci            best = source;
46653a5a1b3Sopenharmony_ci            continue;
46753a5a1b3Sopenharmony_ci        }
46853a5a1b3Sopenharmony_ci
46953a5a1b3Sopenharmony_ci        if (compare_sources(source, best) > 0)
47053a5a1b3Sopenharmony_ci            best = source;
47153a5a1b3Sopenharmony_ci    }
47253a5a1b3Sopenharmony_ci
47353a5a1b3Sopenharmony_ci    old_default_source = core->default_source;
47453a5a1b3Sopenharmony_ci
47553a5a1b3Sopenharmony_ci    if (best == old_default_source)
47653a5a1b3Sopenharmony_ci        return;
47753a5a1b3Sopenharmony_ci
47853a5a1b3Sopenharmony_ci    core->default_source = best;
47953a5a1b3Sopenharmony_ci    pa_log_info("default_source: %s -> %s",
48053a5a1b3Sopenharmony_ci                old_default_source ? old_default_source->name : "(unset)", best ? best->name : "(unset)");
48153a5a1b3Sopenharmony_ci    pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
48253a5a1b3Sopenharmony_ci    pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED], core->default_source);
48353a5a1b3Sopenharmony_ci
48453a5a1b3Sopenharmony_ci    /* try to move the streams from old_default_source to the new default_source conditionally */
48553a5a1b3Sopenharmony_ci    if (old_default_source)
48653a5a1b3Sopenharmony_ci	pa_source_move_streams_to_default_source(core, old_default_source, true);
48753a5a1b3Sopenharmony_ci}
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_civoid pa_core_set_exit_idle_time(pa_core *core, int time) {
49053a5a1b3Sopenharmony_ci    pa_assert(core);
49153a5a1b3Sopenharmony_ci
49253a5a1b3Sopenharmony_ci    if (time == core->exit_idle_time)
49353a5a1b3Sopenharmony_ci        return;
49453a5a1b3Sopenharmony_ci
49553a5a1b3Sopenharmony_ci    pa_log_info("exit_idle_time: %i -> %i", core->exit_idle_time, time);
49653a5a1b3Sopenharmony_ci    core->exit_idle_time = time;
49753a5a1b3Sopenharmony_ci}
49853a5a1b3Sopenharmony_ci
49953a5a1b3Sopenharmony_cistatic void exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
50053a5a1b3Sopenharmony_ci    pa_core *c = userdata;
50153a5a1b3Sopenharmony_ci    pa_assert(c->exit_event == e);
50253a5a1b3Sopenharmony_ci
50353a5a1b3Sopenharmony_ci    pa_log_info("We are idle, quitting...");
50453a5a1b3Sopenharmony_ci    pa_core_exit(c, true, 0);
50553a5a1b3Sopenharmony_ci}
50653a5a1b3Sopenharmony_ci
50753a5a1b3Sopenharmony_civoid pa_core_check_idle(pa_core *c) {
50853a5a1b3Sopenharmony_ci    pa_assert(c);
50953a5a1b3Sopenharmony_ci
51053a5a1b3Sopenharmony_ci    if (!c->exit_event &&
51153a5a1b3Sopenharmony_ci        c->exit_idle_time >= 0 &&
51253a5a1b3Sopenharmony_ci        pa_idxset_size(c->clients) == 0) {
51353a5a1b3Sopenharmony_ci
51453a5a1b3Sopenharmony_ci        c->exit_event = pa_core_rttime_new(c, pa_rtclock_now() + c->exit_idle_time * PA_USEC_PER_SEC, exit_callback, c);
51553a5a1b3Sopenharmony_ci
51653a5a1b3Sopenharmony_ci    } else if (c->exit_event && pa_idxset_size(c->clients) > 0) {
51753a5a1b3Sopenharmony_ci        c->mainloop->time_free(c->exit_event);
51853a5a1b3Sopenharmony_ci        c->exit_event = NULL;
51953a5a1b3Sopenharmony_ci    }
52053a5a1b3Sopenharmony_ci}
52153a5a1b3Sopenharmony_ci
52253a5a1b3Sopenharmony_ciint pa_core_exit(pa_core *c, bool force, int retval) {
52353a5a1b3Sopenharmony_ci    pa_assert(c);
52453a5a1b3Sopenharmony_ci
52553a5a1b3Sopenharmony_ci    if (c->disallow_exit && !force)
52653a5a1b3Sopenharmony_ci        return -1;
52753a5a1b3Sopenharmony_ci
52853a5a1b3Sopenharmony_ci    c->mainloop->quit(c->mainloop, retval);
52953a5a1b3Sopenharmony_ci    return 0;
53053a5a1b3Sopenharmony_ci}
53153a5a1b3Sopenharmony_ci
53253a5a1b3Sopenharmony_civoid pa_core_maybe_vacuum(pa_core *c) {
53353a5a1b3Sopenharmony_ci    pa_assert(c);
53453a5a1b3Sopenharmony_ci
53553a5a1b3Sopenharmony_ci    if (pa_idxset_isempty(c->sink_inputs) && pa_idxset_isempty(c->source_outputs)) {
53653a5a1b3Sopenharmony_ci        pa_log_debug("Hmm, no streams around, trying to vacuum.");
53753a5a1b3Sopenharmony_ci    } else {
53853a5a1b3Sopenharmony_ci        pa_sink *si;
53953a5a1b3Sopenharmony_ci        pa_source *so;
54053a5a1b3Sopenharmony_ci        uint32_t idx;
54153a5a1b3Sopenharmony_ci
54253a5a1b3Sopenharmony_ci        idx = 0;
54353a5a1b3Sopenharmony_ci        PA_IDXSET_FOREACH(si, c->sinks, idx)
54453a5a1b3Sopenharmony_ci            if (si->state != PA_SINK_SUSPENDED)
54553a5a1b3Sopenharmony_ci                return;
54653a5a1b3Sopenharmony_ci
54753a5a1b3Sopenharmony_ci        idx = 0;
54853a5a1b3Sopenharmony_ci        PA_IDXSET_FOREACH(so, c->sources, idx)
54953a5a1b3Sopenharmony_ci            if (so->state != PA_SOURCE_SUSPENDED)
55053a5a1b3Sopenharmony_ci                return;
55153a5a1b3Sopenharmony_ci
55253a5a1b3Sopenharmony_ci        pa_log_info("All sinks and sources are suspended, vacuuming memory");
55353a5a1b3Sopenharmony_ci    }
55453a5a1b3Sopenharmony_ci
55553a5a1b3Sopenharmony_ci    pa_mempool_vacuum(c->mempool);
55653a5a1b3Sopenharmony_ci}
55753a5a1b3Sopenharmony_ci
55853a5a1b3Sopenharmony_cipa_time_event* pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
55953a5a1b3Sopenharmony_ci    struct timeval tv;
56053a5a1b3Sopenharmony_ci
56153a5a1b3Sopenharmony_ci    pa_assert(c);
56253a5a1b3Sopenharmony_ci    pa_assert(c->mainloop);
56353a5a1b3Sopenharmony_ci
56453a5a1b3Sopenharmony_ci    return c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, usec, true), cb, userdata);
56553a5a1b3Sopenharmony_ci}
56653a5a1b3Sopenharmony_ci
56753a5a1b3Sopenharmony_civoid pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) {
56853a5a1b3Sopenharmony_ci    struct timeval tv;
56953a5a1b3Sopenharmony_ci
57053a5a1b3Sopenharmony_ci    pa_assert(c);
57153a5a1b3Sopenharmony_ci    pa_assert(c->mainloop);
57253a5a1b3Sopenharmony_ci
57353a5a1b3Sopenharmony_ci    c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, true));
57453a5a1b3Sopenharmony_ci}
57553a5a1b3Sopenharmony_ci
57653a5a1b3Sopenharmony_civoid pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s) {
57753a5a1b3Sopenharmony_ci    pa_sink_input *si;
57853a5a1b3Sopenharmony_ci    uint32_t idx;
57953a5a1b3Sopenharmony_ci
58053a5a1b3Sopenharmony_ci    pa_assert(c);
58153a5a1b3Sopenharmony_ci    pa_assert(s);
58253a5a1b3Sopenharmony_ci
58353a5a1b3Sopenharmony_ci    PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
58453a5a1b3Sopenharmony_ci        if (si->sink == s)
58553a5a1b3Sopenharmony_ci            continue;
58653a5a1b3Sopenharmony_ci
58753a5a1b3Sopenharmony_ci        if (!si->sink)
58853a5a1b3Sopenharmony_ci            continue;
58953a5a1b3Sopenharmony_ci
59053a5a1b3Sopenharmony_ci        /* Skip this sink input if it is connecting a filter sink to
59153a5a1b3Sopenharmony_ci         * the master */
59253a5a1b3Sopenharmony_ci        if (si->origin_sink)
59353a5a1b3Sopenharmony_ci            continue;
59453a5a1b3Sopenharmony_ci
59553a5a1b3Sopenharmony_ci        /* It might happen that a stream and a sink are set up at the
59653a5a1b3Sopenharmony_ci           same time, in which case we want to make sure we don't
59753a5a1b3Sopenharmony_ci           interfere with that */
59853a5a1b3Sopenharmony_ci        if (!PA_SINK_INPUT_IS_LINKED(si->state))
59953a5a1b3Sopenharmony_ci            continue;
60053a5a1b3Sopenharmony_ci
60153a5a1b3Sopenharmony_ci        if (pa_safe_streq(si->preferred_sink, s->name))
60253a5a1b3Sopenharmony_ci            pa_sink_input_move_to(si, s, false);
60353a5a1b3Sopenharmony_ci    }
60453a5a1b3Sopenharmony_ci
60553a5a1b3Sopenharmony_ci}
60653a5a1b3Sopenharmony_ci
60753a5a1b3Sopenharmony_civoid pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_source *s) {
60853a5a1b3Sopenharmony_ci    pa_source_output *so;
60953a5a1b3Sopenharmony_ci    uint32_t idx;
61053a5a1b3Sopenharmony_ci
61153a5a1b3Sopenharmony_ci    pa_assert(c);
61253a5a1b3Sopenharmony_ci    pa_assert(s);
61353a5a1b3Sopenharmony_ci
61453a5a1b3Sopenharmony_ci    PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
61553a5a1b3Sopenharmony_ci        if (so->source == s)
61653a5a1b3Sopenharmony_ci            continue;
61753a5a1b3Sopenharmony_ci
61853a5a1b3Sopenharmony_ci        if (so->direct_on_input)
61953a5a1b3Sopenharmony_ci            continue;
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_ci        if (!so->source)
62253a5a1b3Sopenharmony_ci            continue;
62353a5a1b3Sopenharmony_ci
62453a5a1b3Sopenharmony_ci        /* Skip this source output if it is connecting a filter source to
62553a5a1b3Sopenharmony_ci         * the master */
62653a5a1b3Sopenharmony_ci        if (so->destination_source)
62753a5a1b3Sopenharmony_ci            continue;
62853a5a1b3Sopenharmony_ci
62953a5a1b3Sopenharmony_ci        /* It might happen that a stream and a source are set up at the
63053a5a1b3Sopenharmony_ci           same time, in which case we want to make sure we don't
63153a5a1b3Sopenharmony_ci           interfere with that */
63253a5a1b3Sopenharmony_ci        if (!PA_SOURCE_OUTPUT_IS_LINKED(so->state))
63353a5a1b3Sopenharmony_ci            continue;
63453a5a1b3Sopenharmony_ci
63553a5a1b3Sopenharmony_ci        if (pa_safe_streq(so->preferred_source, s->name))
63653a5a1b3Sopenharmony_ci            pa_source_output_move_to(so, s, false);
63753a5a1b3Sopenharmony_ci    }
63853a5a1b3Sopenharmony_ci
63953a5a1b3Sopenharmony_ci}
64053a5a1b3Sopenharmony_ci
64153a5a1b3Sopenharmony_ci
64253a5a1b3Sopenharmony_ci/* Helper macro to reduce repetition in pa_suspend_cause_to_string().
64353a5a1b3Sopenharmony_ci * Parameters:
64453a5a1b3Sopenharmony_ci *   char *p: the current position in the write buffer
64553a5a1b3Sopenharmony_ci *   bool first: is cause_to_check the first cause to be written?
64653a5a1b3Sopenharmony_ci *   pa_suspend_cause_t cause_bitfield: the causes given to pa_suspend_cause_to_string()
64753a5a1b3Sopenharmony_ci *   pa_suspend_cause_t cause_to_check: the cause whose presence in cause_bitfield is to be checked
64853a5a1b3Sopenharmony_ci */
64953a5a1b3Sopenharmony_ci#define CHECK_CAUSE(p, first, cause_bitfield, cause_to_check) \
65053a5a1b3Sopenharmony_ci    if (cause_bitfield & PA_SUSPEND_##cause_to_check) {       \
65153a5a1b3Sopenharmony_ci        size_t len = sizeof(#cause_to_check) - 1;             \
65253a5a1b3Sopenharmony_ci        if (!first) {                                         \
65353a5a1b3Sopenharmony_ci            *p = '|';                                         \
65453a5a1b3Sopenharmony_ci            p++;                                              \
65553a5a1b3Sopenharmony_ci        }                                                     \
65653a5a1b3Sopenharmony_ci        first = false;                                        \
65753a5a1b3Sopenharmony_ci        memcpy(p, #cause_to_check, len);                      \
65853a5a1b3Sopenharmony_ci        p += len;                                             \
65953a5a1b3Sopenharmony_ci    }
66053a5a1b3Sopenharmony_ci
66153a5a1b3Sopenharmony_ciconst char *pa_suspend_cause_to_string(pa_suspend_cause_t cause_bitfield, char buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]) {
66253a5a1b3Sopenharmony_ci    char *p = buf;
66353a5a1b3Sopenharmony_ci    bool first = true;
66453a5a1b3Sopenharmony_ci
66553a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, USER);
66653a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, APPLICATION);
66753a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, IDLE);
66853a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, SESSION);
66953a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, PASSTHROUGH);
67053a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, INTERNAL);
67153a5a1b3Sopenharmony_ci    CHECK_CAUSE(p, first, cause_bitfield, UNAVAILABLE);
67253a5a1b3Sopenharmony_ci
67353a5a1b3Sopenharmony_ci    if (p == buf) {
67453a5a1b3Sopenharmony_ci        memcpy(p, "(none)", 6);
67553a5a1b3Sopenharmony_ci        p += 6;
67653a5a1b3Sopenharmony_ci    }
67753a5a1b3Sopenharmony_ci
67853a5a1b3Sopenharmony_ci    *p = 0;
67953a5a1b3Sopenharmony_ci
68053a5a1b3Sopenharmony_ci    return buf;
68153a5a1b3Sopenharmony_ci}
682