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