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