1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16 
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifndef LOG_TAG
26 #define LOG_TAG "Core"
27 #endif
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <signal.h>
32 
33 #include <pulse/rtclock.h>
34 #include <pulse/timeval.h>
35 #include <pulse/xmalloc.h>
36 
37 #include <pulsecore/module.h>
38 #include <pulsecore/core-rtclock.h>
39 #include <pulsecore/core-util.h>
40 #include <pulsecore/message-handler.h>
41 #include <pulsecore/core-scache.h>
42 #include <pulsecore/core-subscribe.h>
43 #include <pulsecore/random.h>
44 #include <pulsecore/log.h>
45 #include <pulsecore/macro.h>
46 #include <pulsecore/strbuf.h>
47 
48 #include "core.h"
49 
50 PA_DEFINE_PUBLIC_CLASS(pa_core, pa_msgobject);
51 
core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk)52 static int core_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) {
53     pa_core *c = PA_CORE(o);
54 
55     pa_core_assert_ref(c);
56 
57     switch (code) {
58 
59         case PA_CORE_MESSAGE_UNLOAD_MODULE:
60             pa_module_unload(userdata, true);
61             return 0;
62 
63         default:
64             return -1;
65     }
66 }
67 
68 static void core_free(pa_object *o);
69 
70 /* Returns a list of handlers. */
message_handler_list(pa_core *c)71 static char *message_handler_list(pa_core *c) {
72     pa_json_encoder *encoder;
73     void *state = NULL;
74     struct pa_message_handler *handler;
75 
76     encoder = pa_json_encoder_new();
77 
78     pa_json_encoder_begin_element_array(encoder);
79     PA_HASHMAP_FOREACH(handler, c->message_handlers, state) {
80         pa_json_encoder_begin_element_object(encoder);
81 
82         pa_json_encoder_add_member_string(encoder, "name", handler->object_path);
83         pa_json_encoder_add_member_string(encoder, "description", handler->description);
84 
85         pa_json_encoder_end_object(encoder);
86     }
87     pa_json_encoder_end_array(encoder);
88 
89     return pa_json_encoder_to_string_free(encoder);
90 }
91 
core_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata)92 static int core_message_handler(const char *object_path, const char *message, const pa_json_object *parameters, char **response, void *userdata) {
93     pa_core *c = userdata;
94 
95     pa_assert(c);
96     pa_assert(message);
97     pa_assert(response);
98     pa_assert(pa_safe_streq(object_path, "/core"));
99 
100     if (pa_streq(message, "list-handlers")) {
101         *response = message_handler_list(c);
102         return PA_OK;
103     }
104 
105     return -PA_ERR_NOTIMPLEMENTED;
106 }
107 
pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size)108 pa_core* pa_core_new(pa_mainloop_api *m, bool shared, bool enable_memfd, size_t shm_size) {
109     pa_log_info("start pa_core_new, shared: %d, enable_memfd: %d", shared, enable_memfd);
110     pa_core* c;
111     pa_mempool *pool;
112     pa_mem_type_t type;
113     int j;
114 
115     pa_assert(m);
116 
117     if (shared) {
118         type = (enable_memfd) ? PA_MEM_TYPE_SHARED_MEMFD : PA_MEM_TYPE_SHARED_POSIX;
119         if (!(pool = pa_mempool_new(type, shm_size, false))) {
120             pa_log_warn("Failed to allocate %s memory pool. Falling back to a normal memory pool.",
121                         pa_mem_type_to_string(type));
122             shared = false;
123         }
124     }
125 
126     if (!shared) {
127         if (!(pool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, shm_size, false))) {
128             pa_log_error("pa_mempool_new() failed.");
129             return NULL;
130         }
131     }
132 
133     c = pa_msgobject_new(pa_core);
134     c->parent.parent.free = core_free;
135     c->parent.process_msg = core_process_msg;
136 
137     c->state = PA_CORE_STARTUP;
138     c->mainloop = m;
139 
140     c->clients = pa_idxset_new(NULL, NULL);
141     c->cards = pa_idxset_new(NULL, NULL);
142     c->sinks = pa_idxset_new(NULL, NULL);
143     c->sources = pa_idxset_new(NULL, NULL);
144     c->sink_inputs = pa_idxset_new(NULL, NULL);
145     c->source_outputs = pa_idxset_new(NULL, NULL);
146     c->modules = pa_idxset_new(NULL, NULL);
147     c->scache = pa_idxset_new(NULL, NULL);
148 
149     c->namereg = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
150     c->shared = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
151     c->message_handlers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
152 
153     pa_message_handler_register(c, "/core", "Core message handler", core_message_handler, (void *) c);
154 
155     c->default_source = NULL;
156     c->default_sink = NULL;
157 
158     c->default_sample_spec.format = PA_SAMPLE_S16NE;
159     c->default_sample_spec.rate = 44100;
160     c->default_sample_spec.channels = 2;
161     pa_channel_map_init_extend(&c->default_channel_map, c->default_sample_spec.channels, PA_CHANNEL_MAP_DEFAULT);
162     c->default_n_fragments = 4;
163     c->default_fragment_size_msec = 25;
164 
165     c->deferred_volume_safety_margin_usec = 8000;
166     c->deferred_volume_extra_delay_usec = 0;
167 
168     c->module_defer_unload_event = NULL;
169     c->modules_pending_unload = pa_hashmap_new(NULL, NULL);
170 
171     c->subscription_defer_event = NULL;
172     PA_LLIST_HEAD_INIT(pa_subscription, c->subscriptions);
173     PA_LLIST_HEAD_INIT(pa_subscription_event, c->subscription_event_queue);
174     c->subscription_event_last = NULL;
175 
176     c->mempool = pool;
177     c->shm_size = shm_size;
178     pa_silence_cache_init(&c->silence_cache);
179 
180     c->exit_event = NULL;
181     c->scache_auto_unload_event = NULL;
182 
183     c->exit_idle_time = -1;
184     c->scache_idle_time = 20;
185 
186     c->flat_volumes = true;
187     c->disallow_module_loading = false;
188     c->disallow_exit = false;
189     c->running_as_daemon = false;
190     c->realtime_scheduling = false;
191     c->realtime_priority = 5;
192     c->disable_remixing = false;
193     c->remixing_use_all_sink_channels = true;
194     c->remixing_produce_lfe = false;
195     c->remixing_consume_lfe = false;
196     c->lfe_crossover_freq = 0;
197     c->deferred_volume = true;
198     c->resample_method = PA_RESAMPLER_SPEEX_FLOAT_BASE + 1;
199 
200     for (j = 0; j < PA_CORE_HOOK_MAX; j++)
201         pa_hook_init(&c->hooks[j], c);
202 
203     pa_random(&c->cookie, sizeof(c->cookie));
204 
205 #ifdef SIGPIPE
206     pa_check_signal_is_blocked(SIGPIPE);
207 #endif
208 
209     return c;
210 }
211 
core_free(pa_object *o)212 static void core_free(pa_object *o) {
213     pa_core *c = PA_CORE(o);
214     int j;
215     pa_assert(c);
216 
217     c->state = PA_CORE_SHUTDOWN;
218 
219     /* Note: All modules and samples in the cache should be unloaded before
220      * we get here */
221 
222     pa_assert(pa_idxset_isempty(c->scache));
223     pa_idxset_free(c->scache, NULL);
224 
225     pa_assert(pa_idxset_isempty(c->modules));
226     pa_idxset_free(c->modules, NULL);
227 
228     pa_assert(pa_idxset_isempty(c->clients));
229     pa_idxset_free(c->clients, NULL);
230 
231     pa_assert(pa_idxset_isempty(c->cards));
232     pa_idxset_free(c->cards, NULL);
233 
234     pa_assert(pa_idxset_isempty(c->sinks));
235     pa_idxset_free(c->sinks, NULL);
236 
237     pa_assert(pa_idxset_isempty(c->sources));
238     pa_idxset_free(c->sources, NULL);
239 
240     pa_assert(pa_idxset_isempty(c->source_outputs));
241     pa_idxset_free(c->source_outputs, NULL);
242 
243     pa_assert(pa_idxset_isempty(c->sink_inputs));
244     pa_idxset_free(c->sink_inputs, NULL);
245 
246     pa_assert(pa_hashmap_isempty(c->namereg));
247     pa_hashmap_free(c->namereg);
248 
249     pa_assert(pa_hashmap_isempty(c->shared));
250     pa_hashmap_free(c->shared);
251 
252     pa_message_handler_unregister(c, "/core");
253 
254     pa_assert(pa_hashmap_isempty(c->message_handlers));
255     pa_hashmap_free(c->message_handlers);
256 
257     pa_assert(pa_hashmap_isempty(c->modules_pending_unload));
258     pa_hashmap_free(c->modules_pending_unload);
259 
260     pa_subscription_free_all(c);
261 
262     if (c->exit_event)
263         c->mainloop->time_free(c->exit_event);
264 
265     pa_assert(!c->default_source);
266     pa_assert(!c->default_sink);
267     pa_xfree(c->configured_default_source);
268     pa_xfree(c->configured_default_sink);
269 
270     pa_silence_cache_done(&c->silence_cache);
271     pa_mempool_unref(c->mempool);
272 
273     for (j = 0; j < PA_CORE_HOOK_MAX; j++)
274         pa_hook_done(&c->hooks[j]);
275 
276     pa_xfree(c);
277 }
278 
pa_core_set_configured_default_sink(pa_core *core, const char *sink)279 void pa_core_set_configured_default_sink(pa_core *core, const char *sink) {
280     char *old_sink;
281 
282     pa_assert(core);
283 
284     old_sink = pa_xstrdup(core->configured_default_sink);
285 
286     if (pa_safe_streq(sink, old_sink))
287         goto finish;
288 
289     pa_xfree(core->configured_default_sink);
290     core->configured_default_sink = pa_xstrdup(sink);
291     pa_log_info("configured_default_sink: %s -> %s",
292                 old_sink ? old_sink : "(unset)", sink ? sink : "(unset)");
293     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
294 
295     pa_core_update_default_sink(core);
296 
297 finish:
298     pa_xfree(old_sink);
299 }
300 
pa_core_set_configured_default_source(pa_core *core, const char *source)301 void pa_core_set_configured_default_source(pa_core *core, const char *source) {
302     char *old_source;
303 
304     pa_assert(core);
305 
306     old_source = pa_xstrdup(core->configured_default_source);
307 
308     if (pa_safe_streq(source, old_source))
309         goto finish;
310 
311     pa_xfree(core->configured_default_source);
312     core->configured_default_source = pa_xstrdup(source);
313     pa_log_info("configured_default_source: %s -> %s",
314                 old_source ? old_source : "(unset)", source ? source : "(unset)");
315     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
316 
317     pa_core_update_default_source(core);
318 
319 finish:
320     pa_xfree(old_source);
321 }
322 
323 /* a  < b  ->  return -1
324  * a == b  ->  return  0
325  * a  > b  ->  return  1 */
compare_sinks(pa_sink *a, pa_sink *b)326 static int compare_sinks(pa_sink *a, pa_sink *b) {
327     pa_core *core;
328 
329     core = a->core;
330 
331     /* Available sinks always beat unavailable sinks. */
332     if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
333             && (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
334         return -1;
335     if (b->active_port && b->active_port->available == PA_AVAILABLE_NO
336             && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
337         return 1;
338 
339     /* The configured default sink is preferred over any other sink. */
340     if (pa_safe_streq(b->name, core->configured_default_sink))
341         return -1;
342     if (pa_safe_streq(a->name, core->configured_default_sink))
343         return 1;
344 
345     if (a->priority < b->priority)
346         return -1;
347     if (a->priority > b->priority)
348         return 1;
349 
350     /* It's hard to find any difference between these sinks, but maybe one of
351      * them is already the default sink? If so, it's best to keep it as the
352      * default to avoid changing the routing for no good reason. */
353     if (b == core->default_sink)
354         return -1;
355     if (a == core->default_sink)
356         return 1;
357 
358     return 0;
359 }
360 
pa_core_update_default_sink(pa_core *core)361 void pa_core_update_default_sink(pa_core *core) {
362     pa_sink *best = NULL;
363     pa_sink *sink;
364     uint32_t idx;
365     pa_sink *old_default_sink;
366 
367     pa_assert(core);
368 
369     PA_IDXSET_FOREACH(sink, core->sinks, idx) {
370         if (!PA_SINK_IS_LINKED(sink->state))
371             continue;
372 
373         if (!best) {
374             best = sink;
375             continue;
376         }
377 
378         if (compare_sinks(sink, best) > 0)
379             best = sink;
380     }
381 
382     old_default_sink = core->default_sink;
383 
384     if (best == old_default_sink)
385         return;
386 
387     core->default_sink = best;
388     pa_log_info("default_sink: %s -> %s",
389                 old_default_sink ? old_default_sink->name : "(unset)", best ? best->name : "(unset)");
390 
391     /* If the default sink changed, it may be that the default source has to be
392      * changed too, because monitor sources are prioritized partly based on the
393      * priorities of the monitored sinks. */
394     pa_core_update_default_source(core);
395 
396     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
397     pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SINK_CHANGED], core->default_sink);
398 
399     /* try to move the streams from old_default_sink to the new default_sink conditionally */
400     if (old_default_sink)
401         pa_sink_move_streams_to_default_sink(core, old_default_sink, true);
402 }
403 
404 /* a  < b  ->  return -1
405  * a == b  ->  return  0
406  * a  > b  ->  return  1 */
compare_sources(pa_source *a, pa_source *b)407 static int compare_sources(pa_source *a, pa_source *b) {
408     pa_core *core;
409 
410     core = a->core;
411 
412     /* Available sources always beat unavailable sources. */
413     if (a->active_port && a->active_port->available == PA_AVAILABLE_NO
414             && (!b->active_port || b->active_port->available != PA_AVAILABLE_NO))
415         return -1;
416     if (b->active_port && b->active_port->available == PA_AVAILABLE_NO
417             && (!a->active_port || a->active_port->available != PA_AVAILABLE_NO))
418         return 1;
419 
420     /* The configured default source is preferred over any other source. */
421     if (pa_safe_streq(b->name, core->configured_default_source))
422         return -1;
423     if (pa_safe_streq(a->name, core->configured_default_source))
424         return 1;
425 
426     /* Monitor sources lose to non-monitor sources. */
427     if (a->monitor_of && !b->monitor_of)
428         return -1;
429     if (!a->monitor_of && b->monitor_of)
430         return 1;
431 
432     if (a->priority < b->priority)
433         return -1;
434     if (a->priority > b->priority)
435         return 1;
436 
437     /* If the sources are monitors, we can compare the monitored sinks. */
438     if (a->monitor_of)
439         return compare_sinks(a->monitor_of, b->monitor_of);
440 
441     /* It's hard to find any difference between these sources, but maybe one of
442      * them is already the default source? If so, it's best to keep it as the
443      * default to avoid changing the routing for no good reason. */
444     if (b == core->default_source)
445         return -1;
446     if (a == core->default_source)
447         return 1;
448 
449     return 0;
450 }
451 
pa_core_update_default_source(pa_core *core)452 void pa_core_update_default_source(pa_core *core) {
453     pa_source *best = NULL;
454     pa_source *source;
455     uint32_t idx;
456     pa_source *old_default_source;
457 
458     pa_assert(core);
459 
460     PA_IDXSET_FOREACH(source, core->sources, idx) {
461         if (!PA_SOURCE_IS_LINKED(source->state))
462             continue;
463 
464         if (!best) {
465             best = source;
466             continue;
467         }
468 
469         if (compare_sources(source, best) > 0)
470             best = source;
471     }
472 
473     old_default_source = core->default_source;
474 
475     if (best == old_default_source)
476         return;
477 
478     core->default_source = best;
479     pa_log_info("default_source: %s -> %s",
480                 old_default_source ? old_default_source->name : "(unset)", best ? best->name : "(unset)");
481     pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SERVER | PA_SUBSCRIPTION_EVENT_CHANGE, PA_INVALID_INDEX);
482     pa_hook_fire(&core->hooks[PA_CORE_HOOK_DEFAULT_SOURCE_CHANGED], core->default_source);
483 
484     /* try to move the streams from old_default_source to the new default_source conditionally */
485     if (old_default_source)
486 	pa_source_move_streams_to_default_source(core, old_default_source, true);
487 }
488 
pa_core_set_exit_idle_time(pa_core *core, int time)489 void pa_core_set_exit_idle_time(pa_core *core, int time) {
490     pa_assert(core);
491 
492     if (time == core->exit_idle_time)
493         return;
494 
495     pa_log_info("exit_idle_time: %i -> %i", core->exit_idle_time, time);
496     core->exit_idle_time = time;
497 }
498 
exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata)499 static void exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
500     pa_core *c = userdata;
501     pa_assert(c->exit_event == e);
502 
503     pa_log_info("We are idle, quitting...");
504     pa_core_exit(c, true, 0);
505 }
506 
pa_core_check_idle(pa_core *c)507 void pa_core_check_idle(pa_core *c) {
508     pa_assert(c);
509 
510     if (!c->exit_event &&
511         c->exit_idle_time >= 0 &&
512         pa_idxset_size(c->clients) == 0) {
513 
514         c->exit_event = pa_core_rttime_new(c, pa_rtclock_now() + c->exit_idle_time * PA_USEC_PER_SEC, exit_callback, c);
515 
516     } else if (c->exit_event && pa_idxset_size(c->clients) > 0) {
517         c->mainloop->time_free(c->exit_event);
518         c->exit_event = NULL;
519     }
520 }
521 
pa_core_exit(pa_core *c, bool force, int retval)522 int pa_core_exit(pa_core *c, bool force, int retval) {
523     pa_assert(c);
524 
525     if (c->disallow_exit && !force)
526         return -1;
527 
528     c->mainloop->quit(c->mainloop, retval);
529     return 0;
530 }
531 
pa_core_maybe_vacuum(pa_core *c)532 void pa_core_maybe_vacuum(pa_core *c) {
533     pa_assert(c);
534 
535     if (pa_idxset_isempty(c->sink_inputs) && pa_idxset_isempty(c->source_outputs)) {
536         pa_log_debug("Hmm, no streams around, trying to vacuum.");
537     } else {
538         pa_sink *si;
539         pa_source *so;
540         uint32_t idx;
541 
542         idx = 0;
543         PA_IDXSET_FOREACH(si, c->sinks, idx)
544             if (si->state != PA_SINK_SUSPENDED)
545                 return;
546 
547         idx = 0;
548         PA_IDXSET_FOREACH(so, c->sources, idx)
549             if (so->state != PA_SOURCE_SUSPENDED)
550                 return;
551 
552         pa_log_info("All sinks and sources are suspended, vacuuming memory");
553     }
554 
555     pa_mempool_vacuum(c->mempool);
556 }
557 
pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata)558 pa_time_event* pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
559     struct timeval tv;
560 
561     pa_assert(c);
562     pa_assert(c->mainloop);
563 
564     return c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, usec, true), cb, userdata);
565 }
566 
pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec)567 void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) {
568     struct timeval tv;
569 
570     pa_assert(c);
571     pa_assert(c->mainloop);
572 
573     c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, true));
574 }
575 
pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s)576 void pa_core_move_streams_to_newly_available_preferred_sink(pa_core *c, pa_sink *s) {
577     pa_sink_input *si;
578     uint32_t idx;
579 
580     pa_assert(c);
581     pa_assert(s);
582 
583     PA_IDXSET_FOREACH(si, c->sink_inputs, idx) {
584         if (si->sink == s)
585             continue;
586 
587         if (!si->sink)
588             continue;
589 
590         /* Skip this sink input if it is connecting a filter sink to
591          * the master */
592         if (si->origin_sink)
593             continue;
594 
595         /* It might happen that a stream and a sink are set up at the
596            same time, in which case we want to make sure we don't
597            interfere with that */
598         if (!PA_SINK_INPUT_IS_LINKED(si->state))
599             continue;
600 
601         if (pa_safe_streq(si->preferred_sink, s->name))
602             pa_sink_input_move_to(si, s, false);
603     }
604 
605 }
606 
pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_source *s)607 void pa_core_move_streams_to_newly_available_preferred_source(pa_core *c, pa_source *s) {
608     pa_source_output *so;
609     uint32_t idx;
610 
611     pa_assert(c);
612     pa_assert(s);
613 
614     PA_IDXSET_FOREACH(so, c->source_outputs, idx) {
615         if (so->source == s)
616             continue;
617 
618         if (so->direct_on_input)
619             continue;
620 
621         if (!so->source)
622             continue;
623 
624         /* Skip this source output if it is connecting a filter source to
625          * the master */
626         if (so->destination_source)
627             continue;
628 
629         /* It might happen that a stream and a source are set up at the
630            same time, in which case we want to make sure we don't
631            interfere with that */
632         if (!PA_SOURCE_OUTPUT_IS_LINKED(so->state))
633             continue;
634 
635         if (pa_safe_streq(so->preferred_source, s->name))
636             pa_source_output_move_to(so, s, false);
637     }
638 
639 }
640 
641 
642 /* Helper macro to reduce repetition in pa_suspend_cause_to_string().
643  * Parameters:
644  *   char *p: the current position in the write buffer
645  *   bool first: is cause_to_check the first cause to be written?
646  *   pa_suspend_cause_t cause_bitfield: the causes given to pa_suspend_cause_to_string()
647  *   pa_suspend_cause_t cause_to_check: the cause whose presence in cause_bitfield is to be checked
648  */
649 #define CHECK_CAUSE(p, first, cause_bitfield, cause_to_check) \
650     if (cause_bitfield & PA_SUSPEND_##cause_to_check) {       \
651         size_t len = sizeof(#cause_to_check) - 1;             \
652         if (!first) {                                         \
653             *p = '|';                                         \
654             p++;                                              \
655         }                                                     \
656         first = false;                                        \
657         memcpy(p, #cause_to_check, len);                      \
658         p += len;                                             \
659     }
660 
pa_suspend_cause_to_string(pa_suspend_cause_t cause_bitfield, char buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE])661 const char *pa_suspend_cause_to_string(pa_suspend_cause_t cause_bitfield, char buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE]) {
662     char *p = buf;
663     bool first = true;
664 
665     CHECK_CAUSE(p, first, cause_bitfield, USER);
666     CHECK_CAUSE(p, first, cause_bitfield, APPLICATION);
667     CHECK_CAUSE(p, first, cause_bitfield, IDLE);
668     CHECK_CAUSE(p, first, cause_bitfield, SESSION);
669     CHECK_CAUSE(p, first, cause_bitfield, PASSTHROUGH);
670     CHECK_CAUSE(p, first, cause_bitfield, INTERNAL);
671     CHECK_CAUSE(p, first, cause_bitfield, UNAVAILABLE);
672 
673     if (p == buf) {
674         memcpy(p, "(none)", 6);
675         p += 6;
676     }
677 
678     *p = 0;
679 
680     return buf;
681 }
682