2253635997ce3ff81b990dc95e4727eb7ebf717b
[platform/upstream/pulseaudio.git] / src / pulsecore / cli-text.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2004-2006 Lennart Poettering
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <pulse/volume.h>
27 #include <pulse/xmalloc.h>
28 #include <pulse/timeval.h>
29
30 #include <pulsecore/module.h>
31 #include <pulsecore/client.h>
32 #include <pulsecore/sink.h>
33 #include <pulsecore/source.h>
34 #include <pulsecore/sink-input.h>
35 #include <pulsecore/source-output.h>
36 #include <pulsecore/strbuf.h>
37 #include <pulsecore/core-scache.h>
38 #include <pulsecore/macro.h>
39 #include <pulsecore/core-util.h>
40
41 #include "cli-text.h"
42
43 char *pa_module_list_to_string(pa_core *c) {
44     pa_strbuf *s;
45     pa_module *m;
46     uint32_t idx = PA_IDXSET_INVALID;
47     pa_assert(c);
48
49     s = pa_strbuf_new();
50
51     pa_strbuf_printf(s, "%u module(s) loaded.\n", pa_idxset_size(c->modules));
52
53     for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) {
54         char *t;
55
56         pa_strbuf_printf(s, "    index: %u\n"
57                          "\tname: <%s>\n"
58                          "\targument: <%s>\n"
59                          "\tused: %i\n"
60                          "\tload once: %s\n",
61                          m->index,
62                          m->name,
63                          pa_strempty(m->argument),
64                          pa_module_get_n_used(m),
65                          pa_yes_no(m->load_once));
66
67         t = pa_proplist_to_string_sep(m->proplist, "\n\t\t");
68         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
69         pa_xfree(t);
70     }
71
72     return pa_strbuf_tostring_free(s);
73 }
74
75 char *pa_client_list_to_string(pa_core *c) {
76     pa_strbuf *s;
77     pa_client *client;
78     uint32_t idx = PA_IDXSET_INVALID;
79     pa_assert(c);
80
81     s = pa_strbuf_new();
82
83     pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients));
84
85     for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) {
86         char *t;
87         pa_strbuf_printf(
88                 s,
89                 "    index: %u\n"
90                 "\tdriver: <%s>\n",
91                 client->index,
92                 client->driver);
93
94         if (client->module)
95             pa_strbuf_printf(s, "\towner module: %u\n", client->module->index);
96
97         t = pa_proplist_to_string_sep(client->proplist, "\n\t\t");
98         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
99         pa_xfree(t);
100     }
101
102     return pa_strbuf_tostring_free(s);
103 }
104
105 static const char *port_available_to_string(pa_port_available_t a) {
106     switch (a) {
107         case PA_PORT_AVAILABLE_UNKNOWN:
108             return "unknown";
109         case PA_PORT_AVAILABLE_NO:
110             return "no";
111         case PA_PORT_AVAILABLE_YES:
112             return "yes";
113         default:
114             return "invalid"; /* Should never happen! */
115     }
116 }
117
118 static void append_port_list(pa_strbuf *s, pa_hashmap *ports)
119 {
120     pa_device_port *p;
121     void *state;
122
123     if (!ports)
124         return;
125
126     pa_strbuf_puts(s, "\tports:\n");
127     PA_HASHMAP_FOREACH(p, ports, state)
128         pa_strbuf_printf(s, "\t\t%s: %s (priority %u, available: %s)\n",
129             p->name, p->description, p->priority, port_available_to_string(p->available));
130 }
131
132 char *pa_card_list_to_string(pa_core *c) {
133     pa_strbuf *s;
134     pa_card *card;
135     uint32_t idx = PA_IDXSET_INVALID;
136     pa_assert(c);
137
138     s = pa_strbuf_new();
139
140     pa_strbuf_printf(s, "%u card(s) available.\n", pa_idxset_size(c->cards));
141
142     for (card = pa_idxset_first(c->cards, &idx); card; card = pa_idxset_next(c->cards, &idx)) {
143         char *t;
144         pa_sink *sink;
145         pa_source *source;
146         uint32_t sidx;
147
148         pa_strbuf_printf(
149                 s,
150                 "    index: %u\n"
151                 "\tname: <%s>\n"
152                 "\tdriver: <%s>\n",
153                 card->index,
154                 card->name,
155                 card->driver);
156
157         if (card->module)
158             pa_strbuf_printf(s, "\towner module: %u\n", card->module->index);
159
160         t = pa_proplist_to_string_sep(card->proplist, "\n\t\t");
161         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
162         pa_xfree(t);
163
164         if (card->profiles) {
165             pa_card_profile *p;
166             void *state;
167
168             pa_strbuf_puts(s, "\tprofiles:\n");
169             PA_HASHMAP_FOREACH(p, card->profiles, state)
170                 pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
171         }
172
173         if (card->active_profile)
174             pa_strbuf_printf(
175                     s,
176                     "\tactive profile: <%s>\n",
177                     card->active_profile->name);
178
179         if (!pa_idxset_isempty(card->sinks)) {
180             pa_strbuf_puts(s, "\tsinks:\n");
181             for (sink = pa_idxset_first(card->sinks, &sidx); sink; sink = pa_idxset_next(card->sinks, &sidx))
182                 pa_strbuf_printf(s, "\t\t%s/#%u: %s\n", sink->name, sink->index, pa_strna(pa_proplist_gets(sink->proplist, PA_PROP_DEVICE_DESCRIPTION)));
183         }
184
185         if (!pa_idxset_isempty(card->sources)) {
186             pa_strbuf_puts(s, "\tsources:\n");
187             for (source = pa_idxset_first(card->sources, &sidx); source; source = pa_idxset_next(card->sources, &sidx))
188                 pa_strbuf_printf(s, "\t\t%s/#%u: %s\n", source->name, source->index, pa_strna(pa_proplist_gets(source->proplist, PA_PROP_DEVICE_DESCRIPTION)));
189         }
190
191         append_port_list(s, card->ports);
192     }
193
194     return pa_strbuf_tostring_free(s);
195 }
196
197 static const char *sink_state_to_string(pa_sink_state_t state) {
198     switch (state) {
199         case PA_SINK_INIT:
200             return "INIT";
201         case PA_SINK_RUNNING:
202             return "RUNNING";
203         case PA_SINK_SUSPENDED:
204             return "SUSPENDED";
205         case PA_SINK_IDLE:
206             return "IDLE";
207         case PA_SINK_UNLINKED:
208             return "UNLINKED";
209         default:
210             return "INVALID";
211     }
212 }
213
214 static const char *source_state_to_string(pa_source_state_t state) {
215     switch (state) {
216         case PA_SOURCE_INIT:
217             return "INIT";
218         case PA_SOURCE_RUNNING:
219             return "RUNNING";
220         case PA_SOURCE_SUSPENDED:
221             return "SUSPENDED";
222         case PA_SOURCE_IDLE:
223             return "IDLE";
224         case PA_SOURCE_UNLINKED:
225             return "UNLINKED";
226         default:
227             return "INVALID";
228     }
229 }
230
231 char *pa_sink_list_to_string(pa_core *c) {
232     pa_strbuf *s;
233     pa_sink *sink;
234     uint32_t idx = PA_IDXSET_INVALID;
235     pa_assert(c);
236
237     s = pa_strbuf_new();
238
239     pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks));
240
241     for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
242         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX],
243             cv[PA_CVOLUME_SNPRINT_MAX],
244             cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
245             v[PA_VOLUME_SNPRINT_MAX],
246             vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
247             cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
248         const char *cmn;
249
250         cmn = pa_channel_map_to_pretty_name(&sink->channel_map);
251
252
253         pa_strbuf_printf(
254             s,
255             "  %c index: %u\n"
256             "\tname: <%s>\n"
257             "\tdriver: <%s>\n"
258             "\tflags: %s%s%s%s%s%s%s%s\n"
259             "\tstate: %s\n"
260             "\tsuspend cause: %s%s%s%s\n"
261             "\tpriority: %u\n"
262             "\tvolume: %s%s%s\n"
263             "\t        balance %0.2f\n"
264             "\tbase volume: %s%s%s\n"
265             "\tvolume steps: %u\n"
266             "\tmuted: %s\n"
267             "\tcurrent latency: %0.2f ms\n"
268             "\tmax request: %lu KiB\n"
269             "\tmax rewind: %lu KiB\n"
270             "\tmonitor source: %u\n"
271             "\tsample spec: %s\n"
272             "\tchannel map: %s%s%s\n"
273             "\tused by: %u\n"
274             "\tlinked by: %u\n",
275             sink == c->default_sink ? '*' : ' ',
276             sink->index,
277             sink->name,
278             sink->driver,
279             sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
280             sink->flags & PA_SINK_NETWORK ? "NETWORK " : "",
281             sink->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
282             sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
283             sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
284             sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
285             sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
286             sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
287             sink_state_to_string(pa_sink_get_state(sink)),
288             sink->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
289             sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "",
290             sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
291             sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
292             sink->priority,
293             pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE)),
294             sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t        " : "",
295             sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE)) : "",
296             pa_cvolume_get_balance(pa_sink_get_volume(sink, FALSE), &sink->channel_map),
297             pa_volume_snprint(v, sizeof(v), sink->base_volume),
298             sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t             " : "",
299             sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), sink->base_volume) : "",
300             sink->n_volume_steps,
301             pa_yes_no(pa_sink_get_mute(sink, FALSE)),
302             (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC,
303             (unsigned long) pa_sink_get_max_request(sink) / 1024,
304             (unsigned long) pa_sink_get_max_rewind(sink) / 1024,
305             sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
306             pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
307             pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
308             cmn ? "\n\t             " : "",
309             cmn ? cmn : "",
310             pa_sink_used_by(sink),
311             pa_sink_linked_by(sink));
312
313         if (sink->flags & PA_SINK_DYNAMIC_LATENCY) {
314             pa_usec_t min_latency, max_latency;
315             pa_sink_get_latency_range(sink, &min_latency, &max_latency);
316
317             pa_strbuf_printf(
318                     s,
319                     "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n",
320                     (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC,
321                     (double) min_latency / PA_USEC_PER_MSEC,
322                     (double) max_latency / PA_USEC_PER_MSEC);
323         } else
324             pa_strbuf_printf(
325                     s,
326                     "\tfixed latency: %0.2f ms\n",
327                     (double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC);
328
329         if (sink->card)
330             pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name);
331         if (sink->module)
332             pa_strbuf_printf(s, "\tmodule: %u\n", sink->module->index);
333
334         t = pa_proplist_to_string_sep(sink->proplist, "\n\t\t");
335         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
336         pa_xfree(t);
337
338         append_port_list(s, sink->ports);
339
340         if (sink->active_port)
341             pa_strbuf_printf(
342                     s,
343                     "\tactive port: <%s>\n",
344                     sink->active_port->name);
345     }
346
347     return pa_strbuf_tostring_free(s);
348 }
349
350 char *pa_source_list_to_string(pa_core *c) {
351     pa_strbuf *s;
352     pa_source *source;
353     uint32_t idx = PA_IDXSET_INVALID;
354     pa_assert(c);
355
356     s = pa_strbuf_new();
357
358     pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources));
359
360     for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
361         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX],
362             cv[PA_CVOLUME_SNPRINT_MAX],
363             cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX],
364             v[PA_VOLUME_SNPRINT_MAX],
365             vdb[PA_SW_VOLUME_SNPRINT_DB_MAX],
366             cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
367         const char *cmn;
368
369         cmn = pa_channel_map_to_pretty_name(&source->channel_map);
370
371         pa_strbuf_printf(
372             s,
373             "  %c index: %u\n"
374             "\tname: <%s>\n"
375             "\tdriver: <%s>\n"
376             "\tflags: %s%s%s%s%s%s%s\n"
377             "\tstate: %s\n"
378             "\tsuspend cause: %s%s%s%s\n"
379             "\tpriority: %u\n"
380             "\tvolume: %s%s%s\n"
381             "\t        balance %0.2f\n"
382             "\tbase volume: %s%s%s\n"
383             "\tvolume steps: %u\n"
384             "\tmuted: %s\n"
385             "\tcurrent latency: %0.2f ms\n"
386             "\tmax rewind: %lu KiB\n"
387             "\tsample spec: %s\n"
388             "\tchannel map: %s%s%s\n"
389             "\tused by: %u\n"
390             "\tlinked by: %u\n",
391             c->default_source == source ? '*' : ' ',
392             source->index,
393             source->name,
394             source->driver,
395             source->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
396             source->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
397             source->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
398             source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
399             source->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
400             source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
401             source->flags & PA_SOURCE_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
402             source_state_to_string(pa_source_get_state(source)),
403             source->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
404             source->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "",
405             source->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
406             source->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
407             source->priority,
408             pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)),
409             source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t        " : "",
410             source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_source_get_volume(source, FALSE)) : "",
411             pa_cvolume_get_balance(pa_source_get_volume(source, FALSE), &source->channel_map),
412             pa_volume_snprint(v, sizeof(v), source->base_volume),
413             source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t             " : "",
414             source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_volume_snprint_dB(vdb, sizeof(vdb), source->base_volume) : "",
415             source->n_volume_steps,
416             pa_yes_no(pa_source_get_mute(source, FALSE)),
417             (double) pa_source_get_latency(source) / PA_USEC_PER_MSEC,
418             (unsigned long) pa_source_get_max_rewind(source) / 1024,
419             pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
420             pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
421             cmn ? "\n\t             " : "",
422             cmn ? cmn : "",
423             pa_source_used_by(source),
424             pa_source_linked_by(source));
425
426         if (source->flags & PA_SOURCE_DYNAMIC_LATENCY) {
427             pa_usec_t min_latency, max_latency;
428             pa_source_get_latency_range(source, &min_latency, &max_latency);
429
430             pa_strbuf_printf(
431                     s,
432                     "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n",
433                     (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC,
434                     (double) min_latency / PA_USEC_PER_MSEC,
435                     (double) max_latency / PA_USEC_PER_MSEC);
436         } else
437             pa_strbuf_printf(
438                     s,
439                     "\tfixed latency: %0.2f ms\n",
440                     (double) pa_source_get_fixed_latency(source) / PA_USEC_PER_MSEC);
441
442         if (source->monitor_of)
443             pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index);
444         if (source->card)
445             pa_strbuf_printf(s, "\tcard: %u <%s>\n", source->card->index, source->card->name);
446         if (source->module)
447             pa_strbuf_printf(s, "\tmodule: %u\n", source->module->index);
448
449         t = pa_proplist_to_string_sep(source->proplist, "\n\t\t");
450         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
451         pa_xfree(t);
452
453         append_port_list(s, source->ports);
454
455         if (source->active_port)
456             pa_strbuf_printf(
457                     s,
458                     "\tactive port: <%s>\n",
459                     source->active_port->name);
460     }
461
462     return pa_strbuf_tostring_free(s);
463 }
464
465
466 char *pa_source_output_list_to_string(pa_core *c) {
467     pa_strbuf *s;
468     pa_source_output *o;
469     uint32_t idx = PA_IDXSET_INVALID;
470     static const char* const state_table[] = {
471         [PA_SOURCE_OUTPUT_INIT] = "INIT",
472         [PA_SOURCE_OUTPUT_RUNNING] = "RUNNING",
473         [PA_SOURCE_OUTPUT_CORKED] = "CORKED",
474         [PA_SOURCE_OUTPUT_UNLINKED] = "UNLINKED"
475     };
476     pa_assert(c);
477
478     s = pa_strbuf_new();
479
480     pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs));
481
482     for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) {
483         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
484         pa_usec_t cl;
485         const char *cmn;
486
487         cmn = pa_channel_map_to_pretty_name(&o->channel_map);
488
489         if ((cl = pa_source_output_get_requested_latency(o)) == (pa_usec_t) -1)
490             pa_snprintf(clt, sizeof(clt), "n/a");
491         else
492             pa_snprintf(clt, sizeof(clt), "%0.2f ms", (double) cl / PA_USEC_PER_MSEC);
493
494         pa_assert(o->source);
495
496         pa_strbuf_printf(
497             s,
498             "    index: %u\n"
499             "\tdriver: <%s>\n"
500             "\tflags: %s%s%s%s%s%s%s%s%s%s%s\n"
501             "\tstate: %s\n"
502             "\tsource: %u <%s>\n"
503             "\tcurrent latency: %0.2f ms\n"
504             "\trequested latency: %s\n"
505             "\tsample spec: %s\n"
506             "\tchannel map: %s%s%s\n"
507             "\tresample method: %s\n",
508             o->index,
509             o->driver,
510             o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
511             o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "",
512             o->flags & PA_SOURCE_OUTPUT_START_CORKED ? "START_CORKED " : "",
513             o->flags & PA_SOURCE_OUTPUT_NO_REMAP ? "NO_REMAP " : "",
514             o->flags & PA_SOURCE_OUTPUT_NO_REMIX ? "NO_REMIX " : "",
515             o->flags & PA_SOURCE_OUTPUT_FIX_FORMAT ? "FIX_FORMAT " : "",
516             o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "",
517             o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
518             o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
519             o->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_ON_SUSPEND " : "",
520             o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
521             state_table[pa_source_output_get_state(o)],
522             o->source->index, o->source->name,
523             (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC,
524             clt,
525             pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
526             pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
527             cmn ? "\n\t             " : "",
528             cmn ? cmn : "",
529             pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
530         if (o->module)
531             pa_strbuf_printf(s, "\towner module: %u\n", o->module->index);
532         if (o->client)
533             pa_strbuf_printf(s, "\tclient: %u <%s>\n", o->client->index, pa_strnull(pa_proplist_gets(o->client->proplist, PA_PROP_APPLICATION_NAME)));
534         if (o->direct_on_input)
535             pa_strbuf_printf(s, "\tdirect on input: %u\n", o->direct_on_input->index);
536
537         t = pa_proplist_to_string_sep(o->proplist, "\n\t\t");
538         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
539         pa_xfree(t);
540     }
541
542     return pa_strbuf_tostring_free(s);
543 }
544
545 char *pa_sink_input_list_to_string(pa_core *c) {
546     pa_strbuf *s;
547     pa_sink_input *i;
548     uint32_t idx = PA_IDXSET_INVALID;
549     static const char* const state_table[] = {
550         [PA_SINK_INPUT_INIT] = "INIT",
551         [PA_SINK_INPUT_RUNNING] = "RUNNING",
552         [PA_SINK_INPUT_DRAINED] = "DRAINED",
553         [PA_SINK_INPUT_CORKED] = "CORKED",
554         [PA_SINK_INPUT_UNLINKED] = "UNLINKED"
555     };
556
557     pa_assert(c);
558     s = pa_strbuf_new();
559
560     pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs));
561
562     for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) {
563         char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
564         pa_usec_t cl;
565         const char *cmn;
566         pa_cvolume v;
567         char *volume_str = NULL;
568
569         cmn = pa_channel_map_to_pretty_name(&i->channel_map);
570
571         if ((cl = pa_sink_input_get_requested_latency(i)) == (pa_usec_t) -1)
572             pa_snprintf(clt, sizeof(clt), "n/a");
573         else
574             pa_snprintf(clt, sizeof(clt), "%0.2f ms", (double) cl / PA_USEC_PER_MSEC);
575
576         pa_assert(i->sink);
577
578         if (pa_sink_input_is_volume_readable(i)) {
579             pa_sink_input_get_volume(i, &v, TRUE);
580             volume_str = pa_sprintf_malloc("%s\n\t        %s\n\t        balance %0.2f",
581                                            pa_cvolume_snprint(cv, sizeof(cv), &v),
582                                            pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &v),
583                                            pa_cvolume_get_balance(&v, &i->channel_map));
584         } else
585             volume_str = pa_xstrdup("n/a");
586
587         pa_strbuf_printf(
588             s,
589             "    index: %u\n"
590             "\tdriver: <%s>\n"
591             "\tflags: %s%s%s%s%s%s%s%s%s%s%s\n"
592             "\tstate: %s\n"
593             "\tsink: %u <%s>\n"
594             "\tvolume: %s\n"
595             "\tmuted: %s\n"
596             "\tcurrent latency: %0.2f ms\n"
597             "\trequested latency: %s\n"
598             "\tsample spec: %s\n"
599             "\tchannel map: %s%s%s\n"
600             "\tresample method: %s\n",
601             i->index,
602             i->driver,
603             i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
604             i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "",
605             i->flags & PA_SINK_INPUT_START_CORKED ? "START_CORKED " : "",
606             i->flags & PA_SINK_INPUT_NO_REMAP ? "NO_REMAP " : "",
607             i->flags & PA_SINK_INPUT_NO_REMIX ? "NO_REMIX " : "",
608             i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "",
609             i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "",
610             i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
611             i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
612             i->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_SUSPEND " : "",
613             i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
614             state_table[pa_sink_input_get_state(i)],
615             i->sink->index, i->sink->name,
616             volume_str,
617             pa_yes_no(pa_sink_input_get_mute(i)),
618             (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
619             clt,
620             pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
621             pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
622             cmn ? "\n\t             " : "",
623             cmn ? cmn : "",
624             pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
625
626         pa_xfree(volume_str);
627
628         if (i->module)
629             pa_strbuf_printf(s, "\tmodule: %u\n", i->module->index);
630         if (i->client)
631             pa_strbuf_printf(s, "\tclient: %u <%s>\n", i->client->index, pa_strnull(pa_proplist_gets(i->client->proplist, PA_PROP_APPLICATION_NAME)));
632
633         t = pa_proplist_to_string_sep(i->proplist, "\n\t\t");
634         pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
635         pa_xfree(t);
636     }
637
638     return pa_strbuf_tostring_free(s);
639 }
640
641 char *pa_scache_list_to_string(pa_core *c) {
642     pa_strbuf *s;
643     pa_assert(c);
644
645     s = pa_strbuf_new();
646
647     pa_strbuf_printf(s, "%u cache entrie(s) available.\n", c->scache ? pa_idxset_size(c->scache) : 0);
648
649     if (c->scache) {
650         pa_scache_entry *e;
651         uint32_t idx = PA_IDXSET_INVALID;
652
653         for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) {
654             double l = 0;
655             char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cvdb[PA_SW_CVOLUME_SNPRINT_DB_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a", *t;
656             const char *cmn;
657
658             cmn = pa_channel_map_to_pretty_name(&e->channel_map);
659
660             if (e->memchunk.memblock) {
661                 pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec);
662                 pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map);
663                 l = (double) e->memchunk.length / (double) pa_bytes_per_second(&e->sample_spec);
664             }
665
666             pa_strbuf_printf(
667                 s,
668                 "    name: <%s>\n"
669                 "\tindex: %u\n"
670                 "\tsample spec: %s\n"
671                 "\tchannel map: %s%s%s\n"
672                 "\tlength: %lu\n"
673                 "\tduration: %0.1f s\n"
674                 "\tvolume: %s\n"
675                 "\t        %s\n"
676                 "\t        balance %0.2f\n"
677                 "\tlazy: %s\n"
678                 "\tfilename: <%s>\n",
679                 e->name,
680                 e->index,
681                 ss,
682                 cm,
683                 cmn ? "\n\t             " : "",
684                 cmn ? cmn : "",
685                 (long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0),
686                 l,
687                 e->volume_is_set ? pa_cvolume_snprint(cv, sizeof(cv), &e->volume) : "n/a",
688                 e->volume_is_set ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), &e->volume) : "n/a",
689                 (e->memchunk.memblock && e->volume_is_set) ? pa_cvolume_get_balance(&e->volume, &e->channel_map) : 0.0f,
690                 pa_yes_no(e->lazy),
691                 e->filename ? e->filename : "n/a");
692
693             t = pa_proplist_to_string_sep(e->proplist, "\n\t\t");
694             pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
695             pa_xfree(t);
696         }
697     }
698
699     return pa_strbuf_tostring_free(s);
700 }
701
702 char *pa_full_status_string(pa_core *c) {
703     pa_strbuf *s;
704     int i;
705
706     s = pa_strbuf_new();
707
708     for (i = 0; i < 8; i++) {
709         char *t = NULL;
710
711         switch (i) {
712             case 0:
713                 t = pa_sink_list_to_string(c);
714                 break;
715             case 1:
716                 t = pa_source_list_to_string(c);
717                 break;
718             case 2:
719                 t = pa_sink_input_list_to_string(c);
720                 break;
721             case 3:
722                 t = pa_source_output_list_to_string(c);
723                 break;
724             case 4:
725                 t = pa_client_list_to_string(c);
726                 break;
727             case 5:
728                 t = pa_card_list_to_string(c);
729                 break;
730             case 6:
731                 t = pa_module_list_to_string(c);
732                 break;
733             case 7:
734                 t = pa_scache_list_to_string(c);
735                 break;
736         }
737
738         pa_strbuf_puts(s, t);
739         pa_xfree(t);
740     }
741
742     return pa_strbuf_tostring_free(s);
743 }