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