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, see <http://www.gnu.org/licenses/>.
18***/
19
20#ifdef HAVE_CONFIG_H
21#include <config.h>
22#endif
23
24#include <pulse/volume.h>
25#include <pulse/xmalloc.h>
26#include <pulse/timeval.h>
27
28#include <pulsecore/module.h>
29#include <pulsecore/client.h>
30#include <pulsecore/card.h>
31#include <pulsecore/sink.h>
32#include <pulsecore/source.h>
33#include <pulsecore/sink-input.h>
34#include <pulsecore/source-output.h>
35#include <pulsecore/strbuf.h>
36#include <pulsecore/core-scache.h>
37#include <pulsecore/macro.h>
38#include <pulsecore/core-util.h>
39#include <pulsecore/namereg.h>
40
41#include "cli-text.h"
42
43char *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    PA_IDXSET_FOREACH(m, 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_to_string_free(s);
73}
74
75char *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    PA_IDXSET_FOREACH(client, 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_to_string_free(s);
103}
104
105static void append_port_list(pa_strbuf *s, pa_hashmap *ports) {
106    pa_device_port *p;
107    void *state;
108
109    pa_assert(ports);
110
111    if (pa_hashmap_isempty(ports))
112        return;
113
114    pa_strbuf_puts(s, "\tports:\n");
115    PA_HASHMAP_FOREACH(p, ports, state) {
116        char *t = pa_proplist_to_string_sep(p->proplist, "\n\t\t\t\t");
117        pa_strbuf_printf(s, "\t\t%s: %s (priority %u, latency offset %" PRId64 " usec, available: %s)\n",
118            p->name, p->description, p->priority, p->latency_offset,
119            pa_available_to_string(p->available));
120        pa_strbuf_printf(s, "\t\t\tproperties:\n\t\t\t\t%s\n", t);
121        pa_xfree(t);
122    }
123}
124
125char *pa_card_list_to_string(pa_core *c) {
126    pa_strbuf *s;
127    pa_card *card;
128    uint32_t idx = PA_IDXSET_INVALID;
129    pa_assert(c);
130
131    s = pa_strbuf_new();
132
133    pa_strbuf_printf(s, "%u card(s) available.\n", pa_idxset_size(c->cards));
134
135    PA_IDXSET_FOREACH(card, c->cards, idx) {
136        char *t;
137        pa_sink *sink;
138        pa_source *source;
139        uint32_t sidx;
140        pa_card_profile *profile;
141        void *state;
142
143        pa_strbuf_printf(
144                s,
145                "    index: %u\n"
146                "\tname: <%s>\n"
147                "\tdriver: <%s>\n",
148                card->index,
149                card->name,
150                card->driver);
151
152        if (card->module)
153            pa_strbuf_printf(s, "\towner module: %u\n", card->module->index);
154
155        t = pa_proplist_to_string_sep(card->proplist, "\n\t\t");
156        pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
157        pa_xfree(t);
158
159        pa_strbuf_puts(s, "\tprofiles:\n");
160        PA_HASHMAP_FOREACH(profile, card->profiles, state)
161            pa_strbuf_printf(s, "\t\t%s: %s (priority %u, available: %s)\n", profile->name, profile->description,
162                             profile->priority, pa_available_to_string(profile->available));
163
164        pa_strbuf_printf(
165                s,
166                "\tactive profile: <%s>\n",
167                card->active_profile->name);
168
169        if (!pa_idxset_isempty(card->sinks)) {
170            pa_strbuf_puts(s, "\tsinks:\n");
171            PA_IDXSET_FOREACH(sink, card->sinks, sidx)
172                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)));
173        }
174
175        if (!pa_idxset_isempty(card->sources)) {
176            pa_strbuf_puts(s, "\tsources:\n");
177            PA_IDXSET_FOREACH(source, card->sources, sidx)
178                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)));
179        }
180
181        append_port_list(s, card->ports);
182    }
183
184    return pa_strbuf_to_string_free(s);
185}
186
187char *pa_sink_list_to_string(pa_core *c) {
188    pa_strbuf *s;
189    pa_sink *sink;
190    uint32_t idx = PA_IDXSET_INVALID;
191    pa_assert(c);
192
193    s = pa_strbuf_new();
194
195    pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks));
196
197    PA_IDXSET_FOREACH(sink, c->sinks, idx) {
198        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX],
199            cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
200            v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
201            cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
202        const char *cmn;
203        char suspend_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE];
204
205        cmn = pa_channel_map_to_pretty_name(&sink->channel_map);
206
207        pa_strbuf_printf(
208            s,
209            "  %c index: %u\n"
210            "\tname: <%s>\n"
211            "\tdriver: <%s>\n"
212            "\tflags: %s%s%s%s%s%s%s%s\n"
213            "\tstate: %s\n"
214            "\tsuspend cause: %s\n"
215            "\tpriority: %u\n"
216            "\tvolume: %s\n"
217            "\t        balance %0.2f\n"
218            "\tbase volume: %s\n"
219            "\tvolume steps: %u\n"
220            "\tmuted: %s\n"
221            "\tcurrent latency: %0.2f ms\n"
222            "\tmax request: %lu KiB\n"
223            "\tmax rewind: %lu KiB\n"
224            "\tmonitor source: %u\n"
225            "\tsample spec: %s\n"
226            "\tchannel map: %s%s%s\n"
227            "\tused by: %u\n"
228            "\tlinked by: %u\n",
229            sink == c->default_sink ? '*' : ' ',
230            sink->index,
231            sink->name,
232            sink->driver,
233            sink->flags & PA_SINK_HARDWARE ? "HARDWARE " : "",
234            sink->flags & PA_SINK_NETWORK ? "NETWORK " : "",
235            sink->flags & PA_SINK_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
236            sink->flags & PA_SINK_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
237            sink->flags & PA_SINK_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
238            sink->flags & PA_SINK_LATENCY ? "LATENCY " : "",
239            sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
240            sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
241            pa_sink_state_to_string(sink->state),
242            pa_suspend_cause_to_string(sink->suspend_cause, suspend_cause_buf),
243            sink->priority,
244            pa_cvolume_snprint_verbose(cv,
245                                       sizeof(cv),
246                                       pa_sink_get_volume(sink, false),
247                                       &sink->channel_map,
248                                       sink->flags & PA_SINK_DECIBEL_VOLUME),
249            pa_cvolume_get_balance(pa_sink_get_volume(sink, false), &sink->channel_map),
250            pa_volume_snprint_verbose(v, sizeof(v), sink->base_volume, sink->flags & PA_SINK_DECIBEL_VOLUME),
251            sink->n_volume_steps,
252            pa_yes_no(pa_sink_get_mute(sink, false)),
253            (double) pa_sink_get_latency(sink) / (double) PA_USEC_PER_MSEC,
254            (unsigned long) pa_sink_get_max_request(sink) / 1024,
255            (unsigned long) pa_sink_get_max_rewind(sink) / 1024,
256            sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX,
257            pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec),
258            pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map),
259            cmn ? "\n\t             " : "",
260            cmn ? cmn : "",
261            pa_sink_used_by(sink),
262            pa_sink_linked_by(sink));
263
264        if (sink->flags & PA_SINK_DYNAMIC_LATENCY) {
265            pa_usec_t min_latency, max_latency;
266            pa_sink_get_latency_range(sink, &min_latency, &max_latency);
267
268            pa_strbuf_printf(
269                    s,
270                    "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n",
271                    (double) pa_sink_get_requested_latency(sink) / (double) PA_USEC_PER_MSEC,
272                    (double) min_latency / PA_USEC_PER_MSEC,
273                    (double) max_latency / PA_USEC_PER_MSEC);
274        } else
275            pa_strbuf_printf(
276                    s,
277                    "\tfixed latency: %0.2f ms\n",
278                    (double) pa_sink_get_fixed_latency(sink) / PA_USEC_PER_MSEC);
279
280        if (sink->card)
281            pa_strbuf_printf(s, "\tcard: %u <%s>\n", sink->card->index, sink->card->name);
282        if (sink->module)
283            pa_strbuf_printf(s, "\tmodule: %u\n", sink->module->index);
284
285        t = pa_proplist_to_string_sep(sink->proplist, "\n\t\t");
286        pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
287        pa_xfree(t);
288
289        append_port_list(s, sink->ports);
290
291        if (sink->active_port)
292            pa_strbuf_printf(
293                    s,
294                    "\tactive port: <%s>\n",
295                    sink->active_port->name);
296    }
297
298    return pa_strbuf_to_string_free(s);
299}
300
301char *pa_source_list_to_string(pa_core *c) {
302    pa_strbuf *s;
303    pa_source *source;
304    uint32_t idx = PA_IDXSET_INVALID;
305    pa_assert(c);
306
307    s = pa_strbuf_new();
308
309    pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources));
310
311    PA_IDXSET_FOREACH(source, c->sources, idx) {
312        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX],
313            cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX],
314            v[PA_VOLUME_SNPRINT_VERBOSE_MAX],
315            cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t;
316        const char *cmn;
317        char suspend_cause_buf[PA_SUSPEND_CAUSE_TO_STRING_BUF_SIZE];
318
319        cmn = pa_channel_map_to_pretty_name(&source->channel_map);
320
321        pa_strbuf_printf(
322            s,
323            "  %c index: %u\n"
324            "\tname: <%s>\n"
325            "\tdriver: <%s>\n"
326            "\tflags: %s%s%s%s%s%s%s\n"
327            "\tstate: %s\n"
328            "\tsuspend cause: %s\n"
329            "\tpriority: %u\n"
330            "\tvolume: %s\n"
331            "\t        balance %0.2f\n"
332            "\tbase volume: %s\n"
333            "\tvolume steps: %u\n"
334            "\tmuted: %s\n"
335            "\tcurrent latency: %0.2f ms\n"
336            "\tmax rewind: %lu KiB\n"
337            "\tsample spec: %s\n"
338            "\tchannel map: %s%s%s\n"
339            "\tused by: %u\n"
340            "\tlinked by: %u\n",
341            source == c->default_source ? '*' : ' ',
342            source->index,
343            source->name,
344            source->driver,
345            source->flags & PA_SOURCE_HARDWARE ? "HARDWARE " : "",
346            source->flags & PA_SOURCE_NETWORK ? "NETWORK " : "",
347            source->flags & PA_SOURCE_HW_MUTE_CTRL ? "HW_MUTE_CTRL " : "",
348            source->flags & PA_SOURCE_HW_VOLUME_CTRL ? "HW_VOLUME_CTRL " : "",
349            source->flags & PA_SOURCE_DECIBEL_VOLUME ? "DECIBEL_VOLUME " : "",
350            source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
351            source->flags & PA_SOURCE_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
352            pa_source_state_to_string(source->state),
353            pa_suspend_cause_to_string(source->suspend_cause, suspend_cause_buf),
354            source->priority,
355            pa_cvolume_snprint_verbose(cv,
356                                       sizeof(cv),
357                                       pa_source_get_volume(source, false),
358                                       &source->channel_map,
359                                       source->flags & PA_SOURCE_DECIBEL_VOLUME),
360            pa_cvolume_get_balance(pa_source_get_volume(source, false), &source->channel_map),
361            pa_volume_snprint_verbose(v, sizeof(v), source->base_volume, source->flags & PA_SOURCE_DECIBEL_VOLUME),
362            source->n_volume_steps,
363            pa_yes_no(pa_source_get_mute(source, false)),
364            (double) pa_source_get_latency(source) / PA_USEC_PER_MSEC,
365            (unsigned long) pa_source_get_max_rewind(source) / 1024,
366            pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec),
367            pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map),
368            cmn ? "\n\t             " : "",
369            cmn ? cmn : "",
370            pa_source_used_by(source),
371            pa_source_linked_by(source));
372
373        if (source->flags & PA_SOURCE_DYNAMIC_LATENCY) {
374            pa_usec_t min_latency, max_latency;
375            pa_source_get_latency_range(source, &min_latency, &max_latency);
376
377            pa_strbuf_printf(
378                    s,
379                    "\tconfigured latency: %0.2f ms; range is %0.2f .. %0.2f ms\n",
380                    (double) pa_source_get_requested_latency(source) / PA_USEC_PER_MSEC,
381                    (double) min_latency / PA_USEC_PER_MSEC,
382                    (double) max_latency / PA_USEC_PER_MSEC);
383        } else
384            pa_strbuf_printf(
385                    s,
386                    "\tfixed latency: %0.2f ms\n",
387                    (double) pa_source_get_fixed_latency(source) / PA_USEC_PER_MSEC);
388
389        if (source->monitor_of)
390            pa_strbuf_printf(s, "\tmonitor_of: %u\n", source->monitor_of->index);
391        if (source->card)
392            pa_strbuf_printf(s, "\tcard: %u <%s>\n", source->card->index, source->card->name);
393        if (source->module)
394            pa_strbuf_printf(s, "\tmodule: %u\n", source->module->index);
395
396        t = pa_proplist_to_string_sep(source->proplist, "\n\t\t");
397        pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
398        pa_xfree(t);
399
400        append_port_list(s, source->ports);
401
402        if (source->active_port)
403            pa_strbuf_printf(
404                    s,
405                    "\tactive port: <%s>\n",
406                    source->active_port->name);
407    }
408
409    return pa_strbuf_to_string_free(s);
410}
411
412char *pa_source_output_list_to_string(pa_core *c) {
413    pa_strbuf *s;
414    pa_source_output *o;
415    uint32_t idx = PA_IDXSET_INVALID;
416    static const char* const state_table[] = {
417        [PA_SOURCE_OUTPUT_INIT] = "INIT",
418        [PA_SOURCE_OUTPUT_RUNNING] = "RUNNING",
419        [PA_SOURCE_OUTPUT_CORKED] = "CORKED",
420        [PA_SOURCE_OUTPUT_UNLINKED] = "UNLINKED"
421    };
422    pa_assert(c);
423
424    s = pa_strbuf_new();
425
426    pa_strbuf_printf(s, "%u source output(s) available.\n", pa_idxset_size(c->source_outputs));
427
428    PA_IDXSET_FOREACH(o, c->source_outputs, idx) {
429        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
430        pa_usec_t cl;
431        const char *cmn;
432        pa_cvolume v;
433        char *volume_str = NULL;
434
435        cmn = pa_channel_map_to_pretty_name(&o->channel_map);
436
437        if ((cl = pa_source_output_get_requested_latency(o)) == (pa_usec_t) -1)
438            pa_snprintf(clt, sizeof(clt), "n/a");
439        else
440            pa_snprintf(clt, sizeof(clt), "%0.2f ms", (double) cl / PA_USEC_PER_MSEC);
441
442        pa_assert(o->source);
443
444        if (pa_source_output_is_volume_readable(o)) {
445            pa_source_output_get_volume(o, &v, true);
446            volume_str = pa_sprintf_malloc("%s\n\t        balance %0.2f",
447                                           pa_cvolume_snprint_verbose(cv, sizeof(cv), &v, &o->channel_map, true),
448                                           pa_cvolume_get_balance(&v, &o->channel_map));
449        } else
450            volume_str = pa_xstrdup("n/a");
451
452        pa_strbuf_printf(
453            s,
454            "    index: %u\n"
455            "\tdriver: <%s>\n"
456            "\tflags: %s%s%s%s%s%s%s%s%s%s%s%s\n"
457            "\tstate: %s\n"
458            "\tsource: %u <%s>\n"
459            "\tvolume: %s\n"
460            "\tmuted: %s\n"
461            "\tcurrent latency: %0.2f ms\n"
462            "\trequested latency: %s\n"
463            "\tsample spec: %s\n"
464            "\tchannel map: %s%s%s\n"
465            "\tresample method: %s\n",
466            o->index,
467            o->driver,
468            o->flags & PA_SOURCE_OUTPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
469            o->flags & PA_SOURCE_OUTPUT_DONT_MOVE ? "DONT_MOVE " : "",
470            o->flags & PA_SOURCE_OUTPUT_START_CORKED ? "START_CORKED " : "",
471            o->flags & PA_SOURCE_OUTPUT_NO_REMAP ? "NO_REMAP " : "",
472            o->flags & PA_SOURCE_OUTPUT_NO_REMIX ? "NO_REMIX " : "",
473            o->flags & PA_SOURCE_OUTPUT_FIX_FORMAT ? "FIX_FORMAT " : "",
474            o->flags & PA_SOURCE_OUTPUT_FIX_RATE ? "FIX_RATE " : "",
475            o->flags & PA_SOURCE_OUTPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
476            o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
477            o->flags & PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_ON_SUSPEND " : "",
478            o->flags & PA_SOURCE_OUTPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
479            o->flags & PA_SOURCE_OUTPUT_PASSTHROUGH ? "PASSTHROUGH " : "",
480            state_table[o->state],
481            o->source->index, o->source->name,
482            volume_str,
483            pa_yes_no(o->muted),
484            (double) pa_source_output_get_latency(o, NULL) / PA_USEC_PER_MSEC,
485            clt,
486            pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
487            pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map),
488            cmn ? "\n\t             " : "",
489            cmn ? cmn : "",
490            pa_resample_method_to_string(pa_source_output_get_resample_method(o)));
491
492        pa_xfree(volume_str);
493
494        if (o->module)
495            pa_strbuf_printf(s, "\towner module: %u\n", o->module->index);
496        if (o->client)
497            pa_strbuf_printf(s, "\tclient: %u <%s>\n", o->client->index, pa_strnull(pa_proplist_gets(o->client->proplist, PA_PROP_APPLICATION_NAME)));
498        if (o->direct_on_input)
499            pa_strbuf_printf(s, "\tdirect on input: %u\n", o->direct_on_input->index);
500
501        t = pa_proplist_to_string_sep(o->proplist, "\n\t\t");
502        pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
503        pa_xfree(t);
504    }
505
506    return pa_strbuf_to_string_free(s);
507}
508
509char *pa_sink_input_list_to_string(pa_core *c) {
510    pa_strbuf *s;
511    pa_sink_input *i;
512    uint32_t idx = PA_IDXSET_INVALID;
513    static const char* const state_table[] = {
514        [PA_SINK_INPUT_INIT] = "INIT",
515        [PA_SINK_INPUT_RUNNING] = "RUNNING",
516        [PA_SINK_INPUT_CORKED] = "CORKED",
517        [PA_SINK_INPUT_UNLINKED] = "UNLINKED"
518    };
519
520    pa_assert(c);
521    s = pa_strbuf_new();
522
523    pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs));
524
525    PA_IDXSET_FOREACH(i, c->sink_inputs, idx) {
526        char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX], *t, clt[28];
527        pa_usec_t cl;
528        const char *cmn;
529        pa_cvolume v;
530        char *volume_str = NULL;
531
532        cmn = pa_channel_map_to_pretty_name(&i->channel_map);
533
534        if ((cl = pa_sink_input_get_requested_latency(i)) == (pa_usec_t) -1)
535            pa_snprintf(clt, sizeof(clt), "n/a");
536        else
537            pa_snprintf(clt, sizeof(clt), "%0.2f ms", (double) cl / PA_USEC_PER_MSEC);
538
539        pa_assert(i->sink);
540
541        if (pa_sink_input_is_volume_readable(i)) {
542            pa_sink_input_get_volume(i, &v, true);
543            volume_str = pa_sprintf_malloc("%s\n\t        balance %0.2f",
544                                           pa_cvolume_snprint_verbose(cv, sizeof(cv), &v, &i->channel_map, true),
545                                           pa_cvolume_get_balance(&v, &i->channel_map));
546        } else
547            volume_str = pa_xstrdup("n/a");
548
549        pa_strbuf_printf(
550            s,
551            "    index: %u\n"
552            "\tdriver: <%s>\n"
553            "\tflags: %s%s%s%s%s%s%s%s%s%s%s%s\n"
554            "\tstate: %s\n"
555            "\tsink: %u <%s>\n"
556            "\tvolume: %s\n"
557            "\tmuted: %s\n"
558            "\tcurrent latency: %0.2f ms\n"
559            "\trequested latency: %s\n"
560            "\tsample spec: %s\n"
561            "\tchannel map: %s%s%s\n"
562            "\tresample method: %s\n",
563            i->index,
564            i->driver,
565            i->flags & PA_SINK_INPUT_VARIABLE_RATE ? "VARIABLE_RATE " : "",
566            i->flags & PA_SINK_INPUT_DONT_MOVE ? "DONT_MOVE " : "",
567            i->flags & PA_SINK_INPUT_START_CORKED ? "START_CORKED " : "",
568            i->flags & PA_SINK_INPUT_NO_REMAP ? "NO_REMAP " : "",
569            i->flags & PA_SINK_INPUT_NO_REMIX ? "NO_REMIX " : "",
570            i->flags & PA_SINK_INPUT_FIX_FORMAT ? "FIX_FORMAT " : "",
571            i->flags & PA_SINK_INPUT_FIX_RATE ? "FIX_RATE " : "",
572            i->flags & PA_SINK_INPUT_FIX_CHANNELS ? "FIX_CHANNELS " : "",
573            i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND ? "DONT_INHIBIT_AUTO_SUSPEND " : "",
574            i->flags & PA_SINK_INPUT_NO_CREATE_ON_SUSPEND ? "NO_CREATE_SUSPEND " : "",
575            i->flags & PA_SINK_INPUT_KILL_ON_SUSPEND ? "KILL_ON_SUSPEND " : "",
576            i->flags & PA_SINK_INPUT_PASSTHROUGH ? "PASSTHROUGH " : "",
577            state_table[i->state],
578            i->sink->index, i->sink->name,
579            volume_str,
580            pa_yes_no(i->muted),
581            (double) pa_sink_input_get_latency(i, NULL) / PA_USEC_PER_MSEC,
582            clt,
583            pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
584            pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
585            cmn ? "\n\t             " : "",
586            cmn ? cmn : "",
587            pa_resample_method_to_string(pa_sink_input_get_resample_method(i)));
588
589        pa_xfree(volume_str);
590
591        if (i->module)
592            pa_strbuf_printf(s, "\tmodule: %u\n", i->module->index);
593        if (i->client)
594            pa_strbuf_printf(s, "\tclient: %u <%s>\n", i->client->index, pa_strnull(pa_proplist_gets(i->client->proplist, PA_PROP_APPLICATION_NAME)));
595
596        t = pa_proplist_to_string_sep(i->proplist, "\n\t\t");
597        pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
598        pa_xfree(t);
599    }
600
601    return pa_strbuf_to_string_free(s);
602}
603
604char *pa_scache_list_to_string(pa_core *c) {
605    pa_strbuf *s;
606    pa_assert(c);
607
608    s = pa_strbuf_new();
609
610    pa_strbuf_printf(s, "%u cache entrie(s) available.\n", c->scache ? pa_idxset_size(c->scache) : 0);
611
612    if (c->scache) {
613        pa_scache_entry *e;
614        uint32_t idx = PA_IDXSET_INVALID;
615
616        PA_IDXSET_FOREACH(e, c->scache, idx) {
617            double l = 0;
618            char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX] = "n/a", *t;
619            const char *cmn;
620
621            cmn = pa_channel_map_to_pretty_name(&e->channel_map);
622
623            if (e->memchunk.memblock) {
624                pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec);
625                pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map);
626                l = (double) e->memchunk.length / (double) pa_bytes_per_second(&e->sample_spec);
627            }
628
629            pa_strbuf_printf(
630                s,
631                "    name: <%s>\n"
632                "\tindex: %u\n"
633                "\tsample spec: %s\n"
634                "\tchannel map: %s%s%s\n"
635                "\tlength: %lu\n"
636                "\tduration: %0.1f s\n"
637                "\tvolume: %s\n"
638                "\t        balance %0.2f\n"
639                "\tlazy: %s\n"
640                "\tfilename: <%s>\n",
641                e->name,
642                e->index,
643                ss,
644                cm,
645                cmn ? "\n\t             " : "",
646                cmn ? cmn : "",
647                (long unsigned)(e->memchunk.memblock ? e->memchunk.length : 0),
648                l,
649                e->volume_is_set ? pa_cvolume_snprint_verbose(cv, sizeof(cv), &e->volume, &e->channel_map, true) : "n/a",
650                (e->memchunk.memblock && e->volume_is_set) ? pa_cvolume_get_balance(&e->volume, &e->channel_map) : 0.0f,
651                pa_yes_no(e->lazy),
652                e->filename ? e->filename : "n/a");
653
654            t = pa_proplist_to_string_sep(e->proplist, "\n\t\t");
655            pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
656            pa_xfree(t);
657        }
658    }
659
660    return pa_strbuf_to_string_free(s);
661}
662
663char *pa_full_status_string(pa_core *c) {
664    pa_strbuf *s;
665    int i;
666
667    s = pa_strbuf_new();
668
669    for (i = 0; i < 8; i++) {
670        char *t = NULL;
671
672        switch (i) {
673            case 0:
674                t = pa_sink_list_to_string(c);
675                break;
676            case 1:
677                t = pa_source_list_to_string(c);
678                break;
679            case 2:
680                t = pa_sink_input_list_to_string(c);
681                break;
682            case 3:
683                t = pa_source_output_list_to_string(c);
684                break;
685            case 4:
686                t = pa_client_list_to_string(c);
687                break;
688            case 5:
689                t = pa_card_list_to_string(c);
690                break;
691            case 6:
692                t = pa_module_list_to_string(c);
693                break;
694            case 7:
695                t = pa_scache_list_to_string(c);
696                break;
697        }
698
699        pa_strbuf_puts(s, t);
700        pa_xfree(t);
701    }
702
703    return pa_strbuf_to_string_free(s);
704}
705