Use simple free function in pa_dynarray_free
[profile/ivi/pulseaudio.git] / src / pulsecore / cli-command.c
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, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <ltdl.h>
33 #include <sys/stat.h>
34 #include <dirent.h>
35 #include <time.h>
36
37 #include <pulse/xmalloc.h>
38 #include <pulse/error.h>
39
40 #include <pulsecore/module.h>
41 #include <pulsecore/sink.h>
42 #include <pulsecore/source.h>
43 #include <pulsecore/client.h>
44 #include <pulsecore/sink-input.h>
45 #include <pulsecore/source-output.h>
46 #include <pulsecore/tokenizer.h>
47 #include <pulsecore/strbuf.h>
48 #include <pulsecore/namereg.h>
49 #include <pulsecore/cli-text.h>
50 #include <pulsecore/core-scache.h>
51 #include <pulsecore/sound-file.h>
52 #include <pulsecore/play-memchunk.h>
53 #include <pulsecore/sound-file-stream.h>
54 #include <pulsecore/shared.h>
55 #include <pulsecore/core-util.h>
56 #include <pulsecore/core-error.h>
57 #include <pulsecore/modinfo.h>
58 #include <pulsecore/dynarray.h>
59
60 #include "cli-command.h"
61
62 struct command {
63     const char *name;
64     int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, pa_bool_t *fail);
65     const char *help;
66     unsigned args;
67 };
68
69 #define META_INCLUDE ".include"
70 #define META_FAIL ".fail"
71 #define META_NOFAIL ".nofail"
72 #define META_IFEXISTS ".ifexists"
73 #define META_ELSE ".else"
74 #define META_ENDIF ".endif"
75
76 enum {
77     IFSTATE_NONE = -1,
78     IFSTATE_FALSE = 0,
79     IFSTATE_TRUE = 1,
80 };
81
82 /* Prototypes for all available commands */
83 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
84 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
85 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
86 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
87 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
88 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
89 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
90 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
91 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
92 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
93 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
94 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
95 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
96 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
97 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
98 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
99 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
100 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
101 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
102 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
103 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
104 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
105 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
106 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
107 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
108 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
109 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
110 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
111 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
112 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
113 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
114 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
115 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
116 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
117 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
118 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
119 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
120 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
121 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
122 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
123 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
124 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
125 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
126 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
127 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
128 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
129 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
130 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
131 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
132 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
133 static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
134
135 /* A method table for all available commands */
136
137 static const struct command commands[] = {
138     { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
139     { "help",                    pa_cli_command_help,               "Show this help",               1 },
140     { "list-modules",            pa_cli_command_modules,            "List loaded modules",          1 },
141     { "list-sinks",              pa_cli_command_sinks,              "List loaded sinks",            1 },
142     { "list-sources",            pa_cli_command_sources,            "List loaded sources",          1 },
143     { "list-clients",            pa_cli_command_clients,            "List loaded clients",          1 },
144     { "list-sink-inputs",        pa_cli_command_sink_inputs,        "List sink inputs",             1 },
145     { "list-source-outputs",     pa_cli_command_source_outputs,     "List source outputs",          1 },
146     { "list-cards",              pa_cli_command_cards,              "List cards",                   1 },
147     { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
148     { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
149     { "ls",                      pa_cli_command_info,               NULL,                           1 },
150     { "list",                    pa_cli_command_info,               NULL,                           1 },
151     { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)", 3},
152     { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)", 2},
153     { "describe-module",         pa_cli_command_describe,           "Describe a module (arg: name)", 2},
154     { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)", 3},
155     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index, volume)", 3},
156     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
157     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, bool)", 3},
158     { "set-sink-input-mute",     pa_cli_command_sink_input_mute,    "Set the mute switch of a sink input (args: index, bool)", 3},
159     { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, bool)", 3},
160     { "update-sink-proplist",    pa_cli_command_update_sink_proplist, "Update the properties of a sink (args: index|name, properties)", 3},
161     { "update-source-proplist",  pa_cli_command_update_source_proplist, "Update the properties of a source (args: index|name, properties)", 3},
162     { "update-sink-input-proplist", pa_cli_command_update_sink_input_proplist, "Update the properties of a sink input (args: index, properties)", 3},
163     { "update-source-output-proplist", pa_cli_command_update_source_output_proplist, "Update the properties of a source_output (args: index, properties)", 3},
164     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
165     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
166     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
167     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
168     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
169     { "list-samples",            pa_cli_command_scache_list,        "List all entries in the sample cache", 1},
170     { "play-sample",             pa_cli_command_scache_play,        "Play a sample from the sample cache (args: name, sink|index)", 3},
171     { "remove-sample",           pa_cli_command_scache_remove,      "Remove a sample from the sample cache (args: name)", 2},
172     { "load-sample",             pa_cli_command_scache_load,        "Load a sound file into the sample cache (args: name, filename)", 3},
173     { "load-sample-lazy",        pa_cli_command_scache_load,        "Lazily load a sound file into the sample cache (args: name, filename)", 3},
174     { "load-sample-dir-lazy",    pa_cli_command_scache_load_dir,    "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
175     { "play-file",               pa_cli_command_play_file,          "Play a sound file (args: filename, sink|index)", 3},
176     { "dump",                    pa_cli_command_dump,               "Dump daemon configuration", 1},
177     { "shared",                  pa_cli_command_list_shared_props,  NULL, 1},
178     { "move-sink-input",         pa_cli_command_move_sink_input,    "Move sink input to another sink (args: index, sink)", 3},
179     { "move-source-output",      pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
180     { "vacuum",                  pa_cli_command_vacuum,             NULL, 1},
181     { "suspend-sink",            pa_cli_command_suspend_sink,       "Suspend sink (args: index|name, bool)", 3},
182     { "suspend-source",          pa_cli_command_suspend_source,     "Suspend source (args: index|name, bool)", 3},
183     { "suspend",                 pa_cli_command_suspend,            "Suspend all sinks and all sources (args: bool)", 2},
184     { "set-card-profile",        pa_cli_command_card_profile,       "Change the profile of a card (args: index, name)", 3},
185     { "set-sink-port",           pa_cli_command_sink_port,          "Change the port of a sink (args: index, name)", 3},
186     { "set-source-port",         pa_cli_command_source_port,        "Change the port of a source (args: index, name)", 3},
187     { "set-log-level",           pa_cli_command_log_level,          "Change the log level (args: numeric level)", 2},
188     { "set-log-meta",            pa_cli_command_log_meta,           "Show source code location in log messages (args: bool)", 2},
189     { "set-log-time",            pa_cli_command_log_time,           "Show timestamps in log messages (args: bool)", 2},
190     { "set-log-backtrace",       pa_cli_command_log_backtrace,      "Show backtrace in log messages (args: frames)", 2},
191     { "dump-volumes",            pa_cli_command_dump_volumes,       NULL, 1 },
192     { NULL, NULL, NULL, 0 }
193 };
194
195 static const char whitespace[] = " \t\n\r";
196 static const char linebreak[] = "\n\r";
197
198 static uint32_t parse_index(const char *n) {
199     uint32_t idx;
200
201     if (pa_atou(n, &idx) < 0)
202         return (uint32_t) PA_IDXSET_INVALID;
203
204     return idx;
205 }
206
207 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
208     pa_core_assert_ref(c);
209     pa_assert(t);
210     pa_assert(buf);
211     pa_assert(fail);
212
213     if (pa_core_exit(c, FALSE, 0) < 0)
214         pa_strbuf_puts(buf, "Not allowed to terminate daemon.\n");
215
216     return 0;
217 }
218
219 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
220     const struct command*command;
221
222     pa_core_assert_ref(c);
223     pa_assert(t);
224     pa_assert(buf);
225     pa_assert(fail);
226
227     pa_strbuf_puts(buf, "Available commands:\n");
228
229     for (command = commands; command->name; command++)
230         if (command->help)
231             pa_strbuf_printf(buf, "    %-25s %s\n", command->name, command->help);
232     return 0;
233 }
234
235 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
236     char *s;
237
238     pa_core_assert_ref(c);
239     pa_assert(t);
240     pa_assert(buf);
241     pa_assert(fail);
242
243     pa_assert_se(s = pa_module_list_to_string(c));
244     pa_strbuf_puts(buf, s);
245     pa_xfree(s);
246     return 0;
247 }
248
249 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
250     char *s;
251
252     pa_core_assert_ref(c);
253     pa_assert(t);
254     pa_assert(buf);
255     pa_assert(fail);
256
257     pa_assert_se(s = pa_client_list_to_string(c));
258     pa_strbuf_puts(buf, s);
259     pa_xfree(s);
260     return 0;
261 }
262
263 static int pa_cli_command_cards(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
264     char *s;
265
266     pa_core_assert_ref(c);
267     pa_assert(t);
268     pa_assert(buf);
269     pa_assert(fail);
270
271     pa_assert_se(s = pa_card_list_to_string(c));
272     pa_strbuf_puts(buf, s);
273     pa_xfree(s);
274     return 0;
275 }
276
277 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
278     char *s;
279
280     pa_core_assert_ref(c);
281     pa_assert(t);
282     pa_assert(buf);
283     pa_assert(fail);
284
285     pa_assert_se(s = pa_sink_list_to_string(c));
286     pa_strbuf_puts(buf, s);
287     pa_xfree(s);
288     return 0;
289 }
290
291 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
292     char *s;
293
294     pa_core_assert_ref(c);
295     pa_assert(t);
296     pa_assert(buf);
297     pa_assert(fail);
298
299     pa_assert_se(s = pa_source_list_to_string(c));
300     pa_strbuf_puts(buf, s);
301     pa_xfree(s);
302     return 0;
303 }
304
305 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
306     char *s;
307
308     pa_core_assert_ref(c);
309     pa_assert(t);
310     pa_assert(buf);
311     pa_assert(fail);
312
313     pa_assert_se(s = pa_sink_input_list_to_string(c));
314     pa_strbuf_puts(buf, s);
315     pa_xfree(s);
316     return 0;
317 }
318
319 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
320     char *s;
321
322     pa_core_assert_ref(c);
323     pa_assert(t);
324     pa_assert(buf);
325     pa_assert(fail);
326
327     pa_assert_se(s = pa_source_output_list_to_string(c));
328     pa_strbuf_puts(buf, s);
329     pa_xfree(s);
330     return 0;
331 }
332
333 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
334     char ss[PA_SAMPLE_SPEC_SNPRINT_MAX];
335     char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
336     char bytes[PA_BYTES_SNPRINT_MAX];
337     const pa_mempool_stat *mstat;
338     unsigned k;
339     pa_sink *def_sink;
340     pa_source *def_source;
341
342     static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
343         [PA_MEMBLOCK_POOL] = "POOL",
344         [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
345         [PA_MEMBLOCK_APPENDED] = "APPENDED",
346         [PA_MEMBLOCK_USER] = "USER",
347         [PA_MEMBLOCK_FIXED] = "FIXED",
348         [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
349     };
350
351     pa_core_assert_ref(c);
352     pa_assert(t);
353     pa_assert(buf);
354     pa_assert(fail);
355
356     mstat = pa_mempool_get_stat(c->mempool);
357
358     pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
359                      (unsigned) pa_atomic_load(&mstat->n_allocated),
360                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->allocated_size)));
361
362     pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
363                      (unsigned) pa_atomic_load(&mstat->n_accumulated),
364                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->accumulated_size)));
365
366     pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
367                      (unsigned) pa_atomic_load(&mstat->n_imported),
368                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->imported_size)));
369
370     pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
371                      (unsigned) pa_atomic_load(&mstat->n_exported),
372                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_atomic_load(&mstat->exported_size)));
373
374     pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
375                      pa_bytes_snprint(bytes, sizeof(bytes), (unsigned) pa_scache_total_size(c)));
376
377     pa_strbuf_printf(buf, "Default sample spec: %s\n",
378                      pa_sample_spec_snprint(ss, sizeof(ss), &c->default_sample_spec));
379
380     pa_strbuf_printf(buf, "Default channel map: %s\n",
381                      pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map));
382
383     def_sink = pa_namereg_get_default_sink(c);
384     def_source = pa_namereg_get_default_source(c);
385     pa_strbuf_printf(buf, "Default sink name: %s\n"
386                      "Default source name: %s\n",
387                      def_sink ? def_sink->name : "none",
388                      def_source ? def_source->name : "none");
389
390     for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
391         pa_strbuf_printf(buf,
392                          "Memory blocks of type %s: %u allocated/%u accumulated.\n",
393                          type_table[k],
394                          (unsigned) pa_atomic_load(&mstat->n_allocated_by_type[k]),
395                          (unsigned) pa_atomic_load(&mstat->n_accumulated_by_type[k]));
396
397     return 0;
398 }
399
400 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
401     pa_core_assert_ref(c);
402     pa_assert(t);
403     pa_assert(buf);
404     pa_assert(fail);
405
406     pa_cli_command_stat(c, t, buf, fail);
407     pa_cli_command_modules(c, t, buf, fail);
408     pa_cli_command_sinks(c, t, buf, fail);
409     pa_cli_command_sources(c, t, buf, fail);
410     pa_cli_command_clients(c, t, buf, fail);
411     pa_cli_command_cards(c, t, buf, fail);
412     pa_cli_command_sink_inputs(c, t, buf, fail);
413     pa_cli_command_source_outputs(c, t, buf, fail);
414     pa_cli_command_scache_list(c, t, buf, fail);
415     return 0;
416 }
417
418 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
419     const char *name;
420
421     pa_core_assert_ref(c);
422     pa_assert(t);
423     pa_assert(buf);
424     pa_assert(fail);
425
426     if (!(name = pa_tokenizer_get(t, 1))) {
427         pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
428         return -1;
429     }
430
431     if (!pa_module_load(c, name,  pa_tokenizer_get(t, 2))) {
432         pa_strbuf_puts(buf, "Module load failed.\n");
433         return -1;
434     }
435
436     return 0;
437 }
438
439 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
440     pa_module *m;
441     uint32_t idx;
442     const char *i;
443     char *e;
444
445     pa_core_assert_ref(c);
446     pa_assert(t);
447     pa_assert(buf);
448     pa_assert(fail);
449
450     if (!(i = pa_tokenizer_get(t, 1))) {
451         pa_strbuf_puts(buf, "You need to specify the module index.\n");
452         return -1;
453     }
454
455     idx = (uint32_t) strtoul(i, &e, 10);
456     if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) {
457         pa_strbuf_puts(buf, "Invalid module index.\n");
458         return -1;
459     }
460
461     pa_module_unload_request(m, FALSE);
462     return 0;
463 }
464
465 static int pa_cli_command_describe(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
466     const char *name;
467     pa_modinfo *i;
468
469     pa_core_assert_ref(c);
470     pa_assert(t);
471     pa_assert(buf);
472     pa_assert(fail);
473
474     if (!(name = pa_tokenizer_get(t, 1))) {
475         pa_strbuf_puts(buf, "You need to specify the module name.\n");
476         return -1;
477     }
478
479     if ((i = pa_modinfo_get_by_name(name))) {
480
481         pa_strbuf_printf(buf, "Name: %s\n", name);
482
483         if (!i->description && !i->version && !i->author && !i->usage)
484             pa_strbuf_printf(buf, "No module information available\n");
485         else {
486             if (i->version)
487                 pa_strbuf_printf(buf, "Version: %s\n", i->version);
488             if (i->description)
489                 pa_strbuf_printf(buf, "Description: %s\n", i->description);
490             if (i->author)
491                 pa_strbuf_printf(buf, "Author: %s\n", i->author);
492             if (i->usage)
493                 pa_strbuf_printf(buf, "Usage: %s\n", i->usage);
494             pa_strbuf_printf(buf, "Load Once: %s\n", pa_yes_no(i->load_once));
495             if (i->deprecated)
496                 pa_strbuf_printf(buf, "Warning, deprecated: %s\n", i->deprecated);
497         }
498
499         pa_modinfo_free(i);
500     } else
501         pa_strbuf_puts(buf, "Failed to open module.\n");
502
503     return 0;
504 }
505
506 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
507     const char *n, *v;
508     pa_sink *sink;
509     uint32_t volume;
510     pa_cvolume cvolume;
511
512     pa_core_assert_ref(c);
513     pa_assert(t);
514     pa_assert(buf);
515     pa_assert(fail);
516
517     if (!(n = pa_tokenizer_get(t, 1))) {
518         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
519         return -1;
520     }
521
522     if (!(v = pa_tokenizer_get(t, 2))) {
523         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
524         return -1;
525     }
526
527     if (pa_atou(v, &volume) < 0) {
528         pa_strbuf_puts(buf, "Failed to parse volume.\n");
529         return -1;
530     }
531
532     if (!PA_VOLUME_IS_VALID(volume)) {
533         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
534         return -1;
535     }
536
537     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
538         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
539         return -1;
540     }
541
542     pa_cvolume_set(&cvolume, 1, volume);
543     pa_sink_set_volume(sink, &cvolume, TRUE, TRUE);
544     return 0;
545 }
546
547 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
548     const char *n, *v;
549     pa_sink_input *si;
550     pa_volume_t volume;
551     pa_cvolume cvolume;
552     uint32_t idx;
553
554     pa_core_assert_ref(c);
555     pa_assert(t);
556     pa_assert(buf);
557     pa_assert(fail);
558
559     if (!(n = pa_tokenizer_get(t, 1))) {
560         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
561         return -1;
562     }
563
564     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
565         pa_strbuf_puts(buf, "Failed to parse index.\n");
566         return -1;
567     }
568
569     if (!(v = pa_tokenizer_get(t, 2))) {
570         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
571         return -1;
572     }
573
574     if (pa_atou(v, &volume) < 0) {
575         pa_strbuf_puts(buf, "Failed to parse volume.\n");
576         return -1;
577     }
578
579     if (!PA_VOLUME_IS_VALID(volume)) {
580         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
581         return -1;
582     }
583
584     if (!(si = pa_idxset_get_by_index(c->sink_inputs, idx))) {
585         pa_strbuf_puts(buf, "No sink input found with this index.\n");
586         return -1;
587     }
588
589     if (!si->volume_writable) {
590         pa_strbuf_puts(buf, "This sink input's volume can't be changed.\n");
591         return -1;
592     }
593
594     pa_cvolume_set(&cvolume, 1, volume);
595     pa_sink_input_set_volume(si, &cvolume, TRUE, TRUE);
596     return 0;
597 }
598
599 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
600     const char *n, *v;
601     pa_source *source;
602     uint32_t volume;
603     pa_cvolume cvolume;
604
605     pa_core_assert_ref(c);
606     pa_assert(t);
607     pa_assert(buf);
608     pa_assert(fail);
609
610     if (!(n = pa_tokenizer_get(t, 1))) {
611         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
612         return -1;
613     }
614
615     if (!(v = pa_tokenizer_get(t, 2))) {
616         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x10000 is normal volume)\n");
617         return -1;
618     }
619
620     if (pa_atou(v, &volume) < 0) {
621         pa_strbuf_puts(buf, "Failed to parse volume.\n");
622         return -1;
623     }
624
625     if (!PA_VOLUME_IS_VALID(volume)) {
626         pa_strbuf_puts(buf, "Volume outside permissible range.\n");
627         return -1;
628     }
629
630     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
631         pa_strbuf_puts(buf, "No source found by this name or index.\n");
632         return -1;
633     }
634
635     pa_cvolume_set(&cvolume, 1, volume);
636     pa_source_set_volume(source, &cvolume, TRUE, TRUE);
637     return 0;
638 }
639
640 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
641     const char *n, *m;
642     pa_sink *sink;
643     int mute;
644
645     pa_core_assert_ref(c);
646     pa_assert(t);
647     pa_assert(buf);
648     pa_assert(fail);
649
650     if (!(n = pa_tokenizer_get(t, 1))) {
651         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
652         return -1;
653     }
654
655     if (!(m = pa_tokenizer_get(t, 2))) {
656         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
657         return -1;
658     }
659
660     if ((mute = pa_parse_boolean(m)) < 0) {
661         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
662         return -1;
663     }
664
665     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
666         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
667         return -1;
668     }
669
670     pa_sink_set_mute(sink, mute, TRUE);
671     return 0;
672 }
673
674 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
675     const char *n, *m;
676     pa_source *source;
677     int mute;
678
679     pa_core_assert_ref(c);
680     pa_assert(t);
681     pa_assert(buf);
682     pa_assert(fail);
683
684     if (!(n = pa_tokenizer_get(t, 1))) {
685         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
686         return -1;
687     }
688
689     if (!(m = pa_tokenizer_get(t, 2))) {
690         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
691         return -1;
692     }
693
694     if ((mute = pa_parse_boolean(m)) < 0) {
695         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
696         return -1;
697     }
698
699     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
700         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
701         return -1;
702     }
703
704     pa_source_set_mute(source, mute, TRUE);
705     return 0;
706 }
707
708 static int pa_cli_command_update_sink_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
709     const char *n, *s;
710     pa_sink *sink;
711     pa_proplist *p;
712
713     pa_core_assert_ref(c);
714     pa_assert(t);
715     pa_assert(buf);
716     pa_assert(fail);
717
718     if (!(n = pa_tokenizer_get(t, 1))) {
719         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
720         return -1;
721     }
722
723     if (!(s = pa_tokenizer_get(t, 2))) {
724         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
725         return -1;
726     }
727
728     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
729         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
730         return -1;
731     }
732
733     if (!(p = pa_proplist_from_string(s))) {
734         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
735         return -1;
736     }
737
738     pa_sink_update_proplist(sink, PA_UPDATE_REPLACE, p);
739
740     pa_proplist_free(p);
741
742     return 0;
743 }
744
745 static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
746     const char *n, *s;
747     pa_source *source;
748     pa_proplist *p;
749
750     pa_core_assert_ref(c);
751     pa_assert(t);
752     pa_assert(buf);
753     pa_assert(fail);
754
755     if (!(n = pa_tokenizer_get(t, 1))) {
756         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
757         return -1;
758     }
759
760     if (!(s = pa_tokenizer_get(t, 2))) {
761         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
762         return -1;
763     }
764
765     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
766         pa_strbuf_puts(buf, "No source found by this name or index.\n");
767         return -1;
768     }
769
770     if (!(p = pa_proplist_from_string(s))) {
771         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
772         return -1;
773     }
774
775     pa_source_update_proplist(source, PA_UPDATE_REPLACE, p);
776
777     pa_proplist_free(p);
778
779     return 0;
780 }
781
782 static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
783     const char *n, *s;
784     pa_sink_input *si;
785     uint32_t idx;
786     pa_proplist *p;
787
788     pa_core_assert_ref(c);
789     pa_assert(t);
790     pa_assert(buf);
791     pa_assert(fail);
792
793     if (!(n = pa_tokenizer_get(t, 1))) {
794         pa_strbuf_puts(buf, "You need to specify a sink input either by index.\n");
795         return -1;
796     }
797
798     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
799         pa_strbuf_puts(buf, "Failed to parse index.\n");
800         return -1;
801     }
802
803     if (!(s = pa_tokenizer_get(t, 2))) {
804         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
805         return -1;
806     }
807
808     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
809         pa_strbuf_puts(buf, "No sink input found with this index.\n");
810         return -1;
811     }
812
813     if (!(p = pa_proplist_from_string(s))) {
814         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
815         return -1;
816     }
817
818     pa_sink_input_update_proplist(si, PA_UPDATE_REPLACE, p);
819
820     pa_proplist_free(p);
821
822     return 0;
823 }
824
825 static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
826     const char *n, *s;
827     pa_source_output *so;
828     uint32_t idx;
829     pa_proplist *p;
830
831     pa_core_assert_ref(c);
832     pa_assert(t);
833     pa_assert(buf);
834     pa_assert(fail);
835
836     if (!(n = pa_tokenizer_get(t, 1))) {
837         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
838         return -1;
839     }
840
841     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
842         pa_strbuf_puts(buf, "Failed to parse index.\n");
843         return -1;
844     }
845
846     if (!(s = pa_tokenizer_get(t, 2))) {
847         pa_strbuf_puts(buf, "You need to specify a \"key=value\" argument.\n");
848         return -1;
849     }
850
851     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
852         pa_strbuf_puts(buf, "No source output found with this index.\n");
853         return -1;
854     }
855
856     if (!(p = pa_proplist_from_string(s))) {
857         pa_strbuf_puts(buf, "Failed to parse proplist.\n");
858         return -1;
859     }
860
861     pa_source_output_update_proplist(so, PA_UPDATE_REPLACE, p);
862
863     pa_proplist_free(p);
864
865     return 0;
866 }
867
868 static int pa_cli_command_sink_input_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
869     const char *n, *v;
870     pa_sink_input *si;
871     uint32_t idx;
872     int mute;
873
874     pa_core_assert_ref(c);
875     pa_assert(t);
876     pa_assert(buf);
877     pa_assert(fail);
878
879     if (!(n = pa_tokenizer_get(t, 1))) {
880         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
881         return -1;
882     }
883
884     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
885         pa_strbuf_puts(buf, "Failed to parse index.\n");
886         return -1;
887     }
888
889     if (!(v = pa_tokenizer_get(t, 2))) {
890         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
891         return -1;
892     }
893
894     if ((mute = pa_parse_boolean(v)) < 0) {
895         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
896         return -1;
897     }
898
899     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
900         pa_strbuf_puts(buf, "No sink input found with this index.\n");
901         return -1;
902     }
903
904     pa_sink_input_set_mute(si, mute, TRUE);
905     return 0;
906 }
907
908 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
909     const char *n;
910     pa_sink *s;
911
912     pa_core_assert_ref(c);
913     pa_assert(t);
914     pa_assert(buf);
915     pa_assert(fail);
916
917     if (!(n = pa_tokenizer_get(t, 1))) {
918         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
919         return -1;
920     }
921
922     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SINK)))
923         pa_namereg_set_default_sink(c, s);
924     else
925         pa_strbuf_printf(buf, "Sink %s does not exist.\n", n);
926
927     return 0;
928 }
929
930 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
931     const char *n;
932     pa_source *s;
933
934     pa_core_assert_ref(c);
935     pa_assert(t);
936     pa_assert(buf);
937     pa_assert(fail);
938
939     if (!(n = pa_tokenizer_get(t, 1))) {
940         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
941         return -1;
942     }
943
944     if ((s = pa_namereg_get(c, n, PA_NAMEREG_SOURCE)))
945         pa_namereg_set_default_source(c, s);
946     else
947         pa_strbuf_printf(buf, "Source %s does not exist.\n", n);
948     return 0;
949 }
950
951 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
952     const char *n;
953     pa_client *client;
954     uint32_t idx;
955
956     pa_core_assert_ref(c);
957     pa_assert(t);
958     pa_assert(buf);
959     pa_assert(fail);
960
961     if (!(n = pa_tokenizer_get(t, 1))) {
962         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
963         return -1;
964     }
965
966     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
967         pa_strbuf_puts(buf, "Failed to parse index.\n");
968         return -1;
969     }
970
971     if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
972         pa_strbuf_puts(buf, "No client found by this index.\n");
973         return -1;
974     }
975
976     pa_client_kill(client);
977     return 0;
978 }
979
980 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
981     const char *n;
982     pa_sink_input *sink_input;
983     uint32_t idx;
984
985     pa_core_assert_ref(c);
986     pa_assert(t);
987     pa_assert(buf);
988     pa_assert(fail);
989
990     if (!(n = pa_tokenizer_get(t, 1))) {
991         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
992         return -1;
993     }
994
995     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
996         pa_strbuf_puts(buf, "Failed to parse index.\n");
997         return -1;
998     }
999
1000     if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
1001         pa_strbuf_puts(buf, "No sink input found by this index.\n");
1002         return -1;
1003     }
1004
1005     pa_sink_input_kill(sink_input);
1006     return 0;
1007 }
1008
1009 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1010     const char *n;
1011     pa_source_output *source_output;
1012     uint32_t idx;
1013
1014     pa_core_assert_ref(c);
1015     pa_assert(t);
1016     pa_assert(buf);
1017     pa_assert(fail);
1018
1019     if (!(n = pa_tokenizer_get(t, 1))) {
1020         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1021         return -1;
1022     }
1023
1024     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1025         pa_strbuf_puts(buf, "Failed to parse index.\n");
1026         return -1;
1027     }
1028
1029     if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
1030         pa_strbuf_puts(buf, "No source output found by this index.\n");
1031         return -1;
1032     }
1033
1034     pa_source_output_kill(source_output);
1035     return 0;
1036 }
1037
1038 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1039     char *s;
1040
1041     pa_core_assert_ref(c);
1042     pa_assert(t);
1043     pa_assert(buf);
1044     pa_assert(fail);
1045
1046     pa_assert_se(s = pa_scache_list_to_string(c));
1047     pa_strbuf_puts(buf, s);
1048     pa_xfree(s);
1049
1050     return 0;
1051 }
1052
1053 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1054     const char *n, *sink_name;
1055     pa_sink *sink;
1056     uint32_t idx;
1057
1058     pa_core_assert_ref(c);
1059     pa_assert(t);
1060     pa_assert(buf);
1061     pa_assert(fail);
1062
1063     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1064         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
1065         return -1;
1066     }
1067
1068     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1069         pa_strbuf_puts(buf, "No sink by that name.\n");
1070         return -1;
1071     }
1072
1073     if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM, NULL, &idx) < 0) {
1074         pa_strbuf_puts(buf, "Failed to play sample.\n");
1075         return -1;
1076     }
1077
1078     pa_strbuf_printf(buf, "Playing on sink input #%i\n", idx);
1079
1080     return 0;
1081 }
1082
1083 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1084     const char *n;
1085
1086     pa_core_assert_ref(c);
1087     pa_assert(t);
1088     pa_assert(buf);
1089     pa_assert(fail);
1090
1091     if (!(n = pa_tokenizer_get(t, 1))) {
1092         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
1093         return -1;
1094     }
1095
1096     if (pa_scache_remove_item(c, n) < 0) {
1097         pa_strbuf_puts(buf, "Failed to remove sample.\n");
1098         return -1;
1099     }
1100
1101     return 0;
1102 }
1103
1104 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1105     const char *fname, *n;
1106     int r;
1107
1108     pa_core_assert_ref(c);
1109     pa_assert(t);
1110     pa_assert(buf);
1111     pa_assert(fail);
1112
1113     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
1114         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
1115         return -1;
1116     }
1117
1118     if (strstr(pa_tokenizer_get(t, 0), "lazy"))
1119         r = pa_scache_add_file_lazy(c, n, fname, NULL);
1120     else
1121         r = pa_scache_add_file(c, n, fname, NULL);
1122
1123     if (r < 0)
1124         pa_strbuf_puts(buf, "Failed to load sound file.\n");
1125
1126     return 0;
1127 }
1128
1129 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1130     const char *pname;
1131
1132     pa_core_assert_ref(c);
1133     pa_assert(t);
1134     pa_assert(buf);
1135     pa_assert(fail);
1136
1137     if (!(pname = pa_tokenizer_get(t, 1))) {
1138         pa_strbuf_puts(buf, "You need to specify a path name.\n");
1139         return -1;
1140     }
1141
1142     if (pa_scache_add_directory_lazy(c, pname) < 0) {
1143         pa_strbuf_puts(buf, "Failed to load directory.\n");
1144         return -1;
1145     }
1146
1147     return 0;
1148 }
1149
1150 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1151     const char *fname, *sink_name;
1152     pa_sink *sink;
1153
1154     pa_core_assert_ref(c);
1155     pa_assert(t);
1156     pa_assert(buf);
1157     pa_assert(fail);
1158
1159     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
1160         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
1161         return -1;
1162     }
1163
1164     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK))) {
1165         pa_strbuf_puts(buf, "No sink by that name.\n");
1166         return -1;
1167     }
1168
1169
1170     return pa_play_file(sink, fname, NULL);
1171 }
1172
1173 static int pa_cli_command_list_shared_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1174     pa_core_assert_ref(c);
1175     pa_assert(t);
1176     pa_assert(buf);
1177     pa_assert(fail);
1178
1179     pa_shared_dump(c, buf);
1180     return 0;
1181 }
1182
1183 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1184     pa_core_assert_ref(c);
1185     pa_assert(t);
1186     pa_assert(buf);
1187     pa_assert(fail);
1188
1189     pa_mempool_vacuum(c->mempool);
1190
1191     return 0;
1192 }
1193
1194 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1195     const char *n, *k;
1196     pa_sink_input *si;
1197     pa_sink *sink;
1198     uint32_t idx;
1199
1200     pa_core_assert_ref(c);
1201     pa_assert(t);
1202     pa_assert(buf);
1203     pa_assert(fail);
1204
1205     if (!(n = pa_tokenizer_get(t, 1))) {
1206         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
1207         return -1;
1208     }
1209
1210     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1211         pa_strbuf_puts(buf, "Failed to parse index.\n");
1212         return -1;
1213     }
1214
1215     if (!(k = pa_tokenizer_get(t, 2))) {
1216         pa_strbuf_puts(buf, "You need to specify a sink.\n");
1217         return -1;
1218     }
1219
1220     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
1221         pa_strbuf_puts(buf, "No sink input found with this index.\n");
1222         return -1;
1223     }
1224
1225     if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK))) {
1226         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1227         return -1;
1228     }
1229
1230     if (pa_sink_input_move_to(si, sink, TRUE) < 0) {
1231         pa_strbuf_puts(buf, "Moved failed.\n");
1232         return -1;
1233     }
1234     return 0;
1235 }
1236
1237 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1238     const char *n, *k;
1239     pa_source_output *so;
1240     pa_source *source;
1241     uint32_t idx;
1242
1243     pa_core_assert_ref(c);
1244     pa_assert(t);
1245     pa_assert(buf);
1246     pa_assert(fail);
1247
1248     if (!(n = pa_tokenizer_get(t, 1))) {
1249         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
1250         return -1;
1251     }
1252
1253     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
1254         pa_strbuf_puts(buf, "Failed to parse index.\n");
1255         return -1;
1256     }
1257
1258     if (!(k = pa_tokenizer_get(t, 2))) {
1259         pa_strbuf_puts(buf, "You need to specify a source.\n");
1260         return -1;
1261     }
1262
1263     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
1264         pa_strbuf_puts(buf, "No source output found with this index.\n");
1265         return -1;
1266     }
1267
1268     if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE))) {
1269         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1270         return -1;
1271     }
1272
1273     if (pa_source_output_move_to(so, source, TRUE) < 0) {
1274         pa_strbuf_puts(buf, "Moved failed.\n");
1275         return -1;
1276     }
1277     return 0;
1278 }
1279
1280 static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1281     const char *n, *m;
1282     pa_sink *sink;
1283     int suspend, r;
1284
1285     pa_core_assert_ref(c);
1286     pa_assert(t);
1287     pa_assert(buf);
1288     pa_assert(fail);
1289
1290     if (!(n = pa_tokenizer_get(t, 1))) {
1291         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1292         return -1;
1293     }
1294
1295     if (!(m = pa_tokenizer_get(t, 2))) {
1296         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1297         return -1;
1298     }
1299
1300     if ((suspend = pa_parse_boolean(m)) < 0) {
1301         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1302         return -1;
1303     }
1304
1305     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1306         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1307         return -1;
1308     }
1309
1310     if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
1311         pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
1312
1313     return 0;
1314 }
1315
1316 static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1317     const char *n, *m;
1318     pa_source *source;
1319     int suspend, r;
1320
1321     pa_core_assert_ref(c);
1322     pa_assert(t);
1323     pa_assert(buf);
1324     pa_assert(fail);
1325
1326     if (!(n = pa_tokenizer_get(t, 1))) {
1327         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1328         return -1;
1329     }
1330
1331     if (!(m = pa_tokenizer_get(t, 2))) {
1332         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1333         return -1;
1334     }
1335
1336     if ((suspend = pa_parse_boolean(m)) < 0) {
1337         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1338         return -1;
1339     }
1340
1341     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1342         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1343         return -1;
1344     }
1345
1346     if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
1347         pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
1348
1349     return 0;
1350 }
1351
1352 static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1353     const char *m;
1354     int suspend, r;
1355
1356     pa_core_assert_ref(c);
1357     pa_assert(t);
1358     pa_assert(buf);
1359     pa_assert(fail);
1360
1361     if (!(m = pa_tokenizer_get(t, 1))) {
1362         pa_strbuf_puts(buf, "You need to specify a suspend switch setting (0/1).\n");
1363         return -1;
1364     }
1365
1366     if ((suspend = pa_parse_boolean(m)) < 0) {
1367         pa_strbuf_puts(buf, "Failed to parse suspend switch.\n");
1368         return -1;
1369     }
1370
1371     if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1372         pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
1373
1374     if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
1375         pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
1376
1377     return 0;
1378 }
1379
1380 static int pa_cli_command_log_level(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1381     const char *m;
1382     uint32_t level;
1383
1384     pa_core_assert_ref(c);
1385     pa_assert(t);
1386     pa_assert(buf);
1387     pa_assert(fail);
1388
1389     if (!(m = pa_tokenizer_get(t, 1))) {
1390         pa_strbuf_puts(buf, "You need to specify a log level (0..4).\n");
1391         return -1;
1392     }
1393
1394     if (pa_atou(m, &level) < 0 || level >= PA_LOG_LEVEL_MAX) {
1395         pa_strbuf_puts(buf, "Failed to parse log level.\n");
1396         return -1;
1397     }
1398
1399     pa_log_set_level(level);
1400
1401     return 0;
1402 }
1403
1404 static int pa_cli_command_log_meta(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1405     const char *m;
1406     pa_bool_t b;
1407
1408     pa_core_assert_ref(c);
1409     pa_assert(t);
1410     pa_assert(buf);
1411     pa_assert(fail);
1412
1413     if (!(m = pa_tokenizer_get(t, 1))) {
1414         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1415         return -1;
1416     }
1417
1418     if ((b = pa_parse_boolean(m)) < 0) {
1419         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1420         return -1;
1421     }
1422
1423     pa_log_set_flags(PA_LOG_PRINT_META, b ? PA_LOG_SET : PA_LOG_UNSET);
1424
1425     return 0;
1426 }
1427
1428 static int pa_cli_command_log_time(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1429     const char *m;
1430     pa_bool_t b;
1431
1432     pa_core_assert_ref(c);
1433     pa_assert(t);
1434     pa_assert(buf);
1435     pa_assert(fail);
1436
1437     if (!(m = pa_tokenizer_get(t, 1))) {
1438         pa_strbuf_puts(buf, "You need to specify a boolean.\n");
1439         return -1;
1440     }
1441
1442     if ((b = pa_parse_boolean(m)) < 0) {
1443         pa_strbuf_puts(buf, "Failed to parse log meta switch.\n");
1444         return -1;
1445     }
1446
1447     pa_log_set_flags(PA_LOG_PRINT_TIME, b ? PA_LOG_SET : PA_LOG_UNSET);
1448
1449     return 0;
1450 }
1451
1452 static int pa_cli_command_log_backtrace(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1453     const char *m;
1454     uint32_t nframes;
1455
1456     pa_core_assert_ref(c);
1457     pa_assert(t);
1458     pa_assert(buf);
1459     pa_assert(fail);
1460
1461     if (!(m = pa_tokenizer_get(t, 1))) {
1462         pa_strbuf_puts(buf, "You need to specify a backtrace level.\n");
1463         return -1;
1464     }
1465
1466     if (pa_atou(m, &nframes) < 0 || nframes >= 1000) {
1467         pa_strbuf_puts(buf, "Failed to parse backtrace level.\n");
1468         return -1;
1469     }
1470
1471     pa_log_set_show_backtrace(nframes);
1472
1473     return 0;
1474 }
1475
1476 static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1477     const char *n, *p;
1478     pa_card *card;
1479
1480     pa_core_assert_ref(c);
1481     pa_assert(t);
1482     pa_assert(buf);
1483     pa_assert(fail);
1484
1485     if (!(n = pa_tokenizer_get(t, 1))) {
1486         pa_strbuf_puts(buf, "You need to specify a card either by its name or its index.\n");
1487         return -1;
1488     }
1489
1490     if (!(p = pa_tokenizer_get(t, 2))) {
1491         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1492         return -1;
1493     }
1494
1495     if (!(card = pa_namereg_get(c, n, PA_NAMEREG_CARD))) {
1496         pa_strbuf_puts(buf, "No card found by this name or index.\n");
1497         return -1;
1498     }
1499
1500     if (pa_card_set_profile(card, p, TRUE) < 0) {
1501         pa_strbuf_printf(buf, "Failed to set card profile to '%s'.\n", p);
1502         return -1;
1503     }
1504
1505     return 0;
1506 }
1507
1508 static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1509     const char *n, *p;
1510     pa_sink *sink;
1511
1512     pa_core_assert_ref(c);
1513     pa_assert(t);
1514     pa_assert(buf);
1515     pa_assert(fail);
1516
1517     if (!(n = pa_tokenizer_get(t, 1))) {
1518         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
1519         return -1;
1520     }
1521
1522     if (!(p = pa_tokenizer_get(t, 2))) {
1523         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1524         return -1;
1525     }
1526
1527     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
1528         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
1529         return -1;
1530     }
1531
1532     if (pa_sink_set_port(sink, p, TRUE) < 0) {
1533         pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
1534         return -1;
1535     }
1536
1537     return 0;
1538 }
1539
1540 static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1541     const char *n, *p;
1542     pa_source *source;
1543
1544     pa_core_assert_ref(c);
1545     pa_assert(t);
1546     pa_assert(buf);
1547     pa_assert(fail);
1548
1549     if (!(n = pa_tokenizer_get(t, 1))) {
1550         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
1551         return -1;
1552     }
1553
1554     if (!(p = pa_tokenizer_get(t, 2))) {
1555         pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
1556         return -1;
1557     }
1558
1559     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
1560         pa_strbuf_puts(buf, "No source found by this name or index.\n");
1561         return -1;
1562     }
1563
1564     if (pa_source_set_port(source, p, TRUE) < 0) {
1565         pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
1566         return -1;
1567     }
1568
1569     return 0;
1570 }
1571
1572 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1573     pa_module *m;
1574     pa_sink *sink;
1575     pa_source *source;
1576     pa_card *card;
1577     pa_bool_t nl;
1578     uint32_t idx;
1579     time_t now;
1580 #ifdef HAVE_CTIME_R
1581     char txt[256];
1582 #endif
1583
1584     pa_core_assert_ref(c);
1585     pa_assert(t);
1586     pa_assert(buf);
1587     pa_assert(fail);
1588
1589     time(&now);
1590
1591 #ifdef HAVE_CTIME_R
1592     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
1593 #else
1594     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
1595 #endif
1596
1597     PA_IDXSET_FOREACH(m, c->modules, idx) {
1598
1599         pa_strbuf_printf(buf, "load-module %s", m->name);
1600
1601         if (m->argument)
1602             pa_strbuf_printf(buf, " %s", m->argument);
1603
1604         pa_strbuf_puts(buf, "\n");
1605     }
1606
1607     nl = FALSE;
1608     PA_IDXSET_FOREACH(sink, c->sinks, idx) {
1609
1610         if (!nl) {
1611             pa_strbuf_puts(buf, "\n");
1612             nl = TRUE;
1613         }
1614
1615         pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_max(pa_sink_get_volume(sink, FALSE)));
1616         pa_strbuf_printf(buf, "set-sink-mute %s %s\n", sink->name, pa_yes_no(pa_sink_get_mute(sink, FALSE)));
1617         pa_strbuf_printf(buf, "suspend-sink %s %s\n", sink->name, pa_yes_no(pa_sink_get_state(sink) == PA_SINK_SUSPENDED));
1618     }
1619
1620     nl = FALSE;
1621     PA_IDXSET_FOREACH(source, c->sources, idx) {
1622
1623         if (!nl) {
1624             pa_strbuf_puts(buf, "\n");
1625             nl = TRUE;
1626         }
1627
1628         pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_max(pa_source_get_volume(source, FALSE)));
1629         pa_strbuf_printf(buf, "set-source-mute %s %s\n", source->name, pa_yes_no(pa_source_get_mute(source, FALSE)));
1630         pa_strbuf_printf(buf, "suspend-source %s %s\n", source->name, pa_yes_no(pa_source_get_state(source) == PA_SOURCE_SUSPENDED));
1631     }
1632
1633     nl = FALSE;
1634     PA_IDXSET_FOREACH(card, c->cards, idx) {
1635
1636         if (!nl) {
1637             pa_strbuf_puts(buf, "\n");
1638             nl = TRUE;
1639         }
1640
1641         if (card->active_profile)
1642             pa_strbuf_printf(buf, "set-card-profile %s %s\n", card->name, card->active_profile->name);
1643     }
1644
1645     nl = FALSE;
1646     if ((sink = pa_namereg_get_default_sink(c))) {
1647         if (!nl) {
1648             pa_strbuf_puts(buf, "\n");
1649             nl = TRUE;
1650         }
1651
1652         pa_strbuf_printf(buf, "set-default-sink %s\n", sink->name);
1653     }
1654
1655     if ((source = pa_namereg_get_default_source(c))) {
1656         if (!nl)
1657             pa_strbuf_puts(buf, "\n");
1658
1659         pa_strbuf_printf(buf, "set-default-source %s\n", source->name);
1660     }
1661
1662     pa_strbuf_puts(buf, "\n### EOF\n");
1663
1664     return 0;
1665 }
1666
1667 static int pa_cli_command_dump_volumes(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
1668     pa_sink *s;
1669     pa_source *so;
1670     pa_sink_input *i;
1671     pa_source_output *o;
1672     uint32_t s_idx, i_idx;
1673     char v_str[PA_CVOLUME_SNPRINT_MAX];
1674
1675     pa_core_assert_ref(c);
1676     pa_assert(t);
1677     pa_assert(buf);
1678     pa_assert(fail);
1679
1680     PA_IDXSET_FOREACH(s, c->sinks, s_idx) {
1681         pa_strbuf_printf(buf, "Sink %d: ", s_idx);
1682         pa_strbuf_printf(buf, "reference = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &s->reference_volume));
1683         pa_strbuf_printf(buf, "real = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &s->real_volume));
1684         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &s->soft_volume));
1685         pa_strbuf_printf(buf, "current_hw = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &s->thread_info.current_hw_volume));
1686         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(s->save_volume));
1687
1688         PA_IDXSET_FOREACH(i, s->inputs, i_idx) {
1689             pa_strbuf_printf(buf, "\tInput %d: ", i_idx);
1690             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->volume));
1691             pa_strbuf_printf(buf, "reference_ratio = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->reference_ratio));
1692             pa_strbuf_printf(buf, "real_ratio = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->real_ratio));
1693             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->soft_volume));
1694             pa_strbuf_printf(buf, "volume_factor = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->volume_factor));
1695             pa_strbuf_printf(buf, "volume_factor_sink = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &i->volume_factor_sink));
1696             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(i->save_volume));
1697         }
1698     }
1699
1700     PA_IDXSET_FOREACH(so, c->sources, s_idx) {
1701         pa_strbuf_printf(buf, "Source %d: ", s_idx);
1702         pa_strbuf_printf(buf, "reference = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &so->reference_volume));
1703         pa_strbuf_printf(buf, "real = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &so->real_volume));
1704         pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &so->soft_volume));
1705         pa_strbuf_printf(buf, "current_hw = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &so->thread_info.current_hw_volume));
1706         pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(so->save_volume));
1707
1708         PA_IDXSET_FOREACH(o, so->outputs, i_idx) {
1709             pa_strbuf_printf(buf, "\tOutput %d: ", i_idx);
1710             pa_strbuf_printf(buf, "volume = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->volume));
1711             pa_strbuf_printf(buf, "reference_ratio = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->reference_ratio));
1712             pa_strbuf_printf(buf, "real_ratio = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->real_ratio));
1713             pa_strbuf_printf(buf, "soft = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->soft_volume));
1714             pa_strbuf_printf(buf, "volume_factor = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->volume_factor));
1715             pa_strbuf_printf(buf, "volume_factor_source = %s, ", pa_cvolume_snprint(v_str, sizeof(v_str), &o->volume_factor_source));
1716             pa_strbuf_printf(buf, "save = %s\n", pa_yes_no(o->save_volume));
1717         }
1718     }
1719
1720     return 0;
1721 }
1722
1723 int pa_cli_command_execute_line_stateful(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail, int *ifstate) {
1724     const char *cs;
1725
1726     pa_assert(c);
1727     pa_assert(s);
1728     pa_assert(buf);
1729
1730     cs = s+strspn(s, whitespace);
1731
1732     if (*cs == '#' || !*cs)
1733         return 0;
1734     else if (*cs == '.') {
1735         if (!strcmp(cs, META_ELSE)) {
1736             if (!ifstate || *ifstate == IFSTATE_NONE) {
1737                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1738                 return -1;
1739             } else if (*ifstate == IFSTATE_TRUE)
1740                 *ifstate = IFSTATE_FALSE;
1741             else
1742                 *ifstate = IFSTATE_TRUE;
1743             return 0;
1744         } else if (!strcmp(cs, META_ENDIF)) {
1745             if (!ifstate || *ifstate == IFSTATE_NONE) {
1746                 pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1747                 return -1;
1748             } else
1749                 *ifstate = IFSTATE_NONE;
1750             return 0;
1751         }
1752         if (ifstate && *ifstate == IFSTATE_FALSE)
1753             return 0;
1754         if (!strcmp(cs, META_FAIL))
1755             *fail = TRUE;
1756         else if (!strcmp(cs, META_NOFAIL))
1757             *fail = FALSE;
1758         else {
1759             size_t l;
1760             l = strcspn(cs, whitespace);
1761
1762             if (l == sizeof(META_INCLUDE)-1 && !strncmp(cs, META_INCLUDE, l)) {
1763                 struct stat st;
1764                 const char *filename = cs+l+strspn(cs+l, whitespace);
1765
1766                 if (stat(filename, &st) < 0) {
1767                     pa_log_warn("stat('%s'): %s", filename, pa_cstrerror(errno));
1768                     if (*fail)
1769                         return -1;
1770                 } else {
1771                     if (S_ISDIR(st.st_mode)) {
1772                         DIR *d;
1773
1774                         if (!(d = opendir(filename))) {
1775                             pa_log_warn("Failed to read '%s': %s", filename, pa_cstrerror(errno));
1776                             if (*fail)
1777                                 return -1;
1778                         } else {
1779                             unsigned i, count;
1780                             char **sorted_files;
1781                             struct dirent *de;
1782                             pa_bool_t failed = FALSE;
1783                             pa_dynarray *files = pa_dynarray_new();
1784
1785                             while ((de = readdir(d))) {
1786                                 char *extn;
1787                                 size_t flen = strlen(de->d_name);
1788
1789                                 if (flen < 4)
1790                                     continue;
1791
1792                                 extn = &de->d_name[flen-3];
1793                                 if (strncmp(extn, ".pa", 3) == 0)
1794                                     pa_dynarray_append(files, pa_sprintf_malloc("%s" PA_PATH_SEP "%s", filename, de->d_name));
1795                             }
1796
1797                             closedir(d);
1798
1799                             count = pa_dynarray_size(files);
1800                             sorted_files = pa_xnew(char*, count);
1801                             for (i = 0; i < count; ++i)
1802                                 sorted_files[i] = pa_dynarray_get(files, i);
1803                             pa_dynarray_free(files, NULL);
1804
1805                             for (i = 0; i < count; ++i) {
1806                                 for (unsigned j = 0; j < count; ++j) {
1807                                     if (strcmp(sorted_files[i], sorted_files[j]) < 0) {
1808                                         char *tmp = sorted_files[i];
1809                                         sorted_files[i] = sorted_files[j];
1810                                         sorted_files[j] = tmp;
1811                                     }
1812                                 }
1813                             }
1814
1815                             for (i = 0; i < count; ++i) {
1816                                 if (!failed) {
1817                                     if (pa_cli_command_execute_file(c, sorted_files[i], buf, fail) < 0 && *fail)
1818                                         failed = TRUE;
1819                                 }
1820
1821                                 pa_xfree(sorted_files[i]);
1822                             }
1823                             pa_xfree(sorted_files);
1824                             if (failed)
1825                                 return -1;
1826                         }
1827                     } else if (pa_cli_command_execute_file(c, filename, buf, fail) < 0 && *fail) {
1828                         return -1;
1829                     }
1830                 }
1831             } else if (l == sizeof(META_IFEXISTS)-1 && !strncmp(cs, META_IFEXISTS, l)) {
1832                 if (!ifstate) {
1833                     pa_strbuf_printf(buf, "Meta command %s is not valid in this context\n", cs);
1834                     return -1;
1835                 } else if (*ifstate != IFSTATE_NONE) {
1836                     pa_strbuf_printf(buf, "Nested %s commands not supported\n", cs);
1837                     return -1;
1838                 } else {
1839                     const char *filename = cs+l+strspn(cs+l, whitespace);
1840
1841                     /* Search DL_SEARCH_PATH unless the filename is absolute */
1842                     if (filename[0] == PA_PATH_SEP_CHAR) {
1843
1844                         *ifstate = access(filename, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
1845                         pa_log_debug("Checking for existence of '%s': %s", filename, *ifstate == IFSTATE_TRUE ? "success" : "failure");
1846
1847                     } else {
1848                         const char *paths, *state = NULL;
1849                         char *p;
1850
1851                         if (!(paths = lt_dlgetsearchpath()))
1852                             return -1;
1853
1854                         while ((p = pa_split(paths, ":", &state))) {
1855                             char *pathname;
1856
1857                             pathname = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", p, filename);
1858                             pa_xfree(p);
1859
1860                             *ifstate = access(pathname, F_OK) == 0 ? IFSTATE_TRUE : IFSTATE_FALSE;
1861                             pa_log_debug("Checking for existence of '%s': %s", pathname, *ifstate == IFSTATE_TRUE ? "success" : "failure");
1862
1863                             pa_xfree(pathname);
1864
1865                             if (*ifstate == IFSTATE_TRUE)
1866                                 break;
1867                         }
1868                     }
1869
1870                 }
1871             } else {
1872                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
1873                 if (*fail) return -1;
1874             }
1875         }
1876     } else {
1877         const struct command*command;
1878         int unknown = 1;
1879         size_t l;
1880
1881         if (ifstate && *ifstate == IFSTATE_FALSE)
1882             return 0;
1883
1884         l = strcspn(cs, whitespace);
1885
1886         for (command = commands; command->name; command++)
1887             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
1888                 int ret;
1889                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
1890                 pa_assert(t);
1891                 ret = command->proc(c, t, buf, fail);
1892                 pa_tokenizer_free(t);
1893                 unknown = 0;
1894
1895                 if (ret < 0 && *fail)
1896                     return -1;
1897
1898                 break;
1899             }
1900
1901         if (unknown) {
1902             pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
1903             if (*fail)
1904                 return -1;
1905         }
1906     }
1907
1908     return 0;
1909 }
1910
1911 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) {
1912     return pa_cli_command_execute_line_stateful(c, s, buf, fail, NULL);
1913 }
1914
1915 int pa_cli_command_execute_file_stream(pa_core *c, FILE *f, pa_strbuf *buf, pa_bool_t *fail) {
1916     char line[2048];
1917     int ifstate = IFSTATE_NONE;
1918     int ret = -1;
1919     pa_bool_t _fail = TRUE;
1920
1921     pa_assert(c);
1922     pa_assert(f);
1923     pa_assert(buf);
1924
1925     if (!fail)
1926         fail = &_fail;
1927
1928     while (fgets(line, sizeof(line), f)) {
1929         pa_strip_nl(line);
1930
1931         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail)
1932             goto fail;
1933     }
1934
1935     ret = 0;
1936
1937 fail:
1938
1939     return ret;
1940 }
1941
1942 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, pa_bool_t *fail) {
1943     FILE *f = NULL;
1944     int ret = -1;
1945     pa_bool_t _fail = TRUE;
1946
1947     pa_assert(c);
1948     pa_assert(fn);
1949     pa_assert(buf);
1950
1951     if (!fail)
1952         fail = &_fail;
1953
1954     if (!(f = pa_fopen_cloexec(fn, "r"))) {
1955         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
1956         if (!*fail)
1957             ret = 0;
1958         goto fail;
1959     }
1960
1961     pa_log_debug("Parsing script '%s'", fn);
1962     ret = pa_cli_command_execute_file_stream(c, f, buf, fail);
1963
1964 fail:
1965     if (f)
1966         fclose(f);
1967
1968     return ret;
1969 }
1970
1971 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, pa_bool_t *fail) {
1972     const char *p;
1973     int ifstate = IFSTATE_NONE;
1974     pa_bool_t _fail = TRUE;
1975
1976     pa_assert(c);
1977     pa_assert(s);
1978     pa_assert(buf);
1979
1980     if (!fail)
1981         fail = &_fail;
1982
1983     p = s;
1984     while (*p) {
1985         size_t l = strcspn(p, linebreak);
1986         char *line = pa_xstrndup(p, l);
1987
1988         if (pa_cli_command_execute_line_stateful(c, line, buf, fail, &ifstate) < 0 && *fail) {
1989             pa_xfree(line);
1990             return -1;
1991         }
1992         pa_xfree(line);
1993
1994         p += l;
1995         p += strspn(p, linebreak);
1996     }
1997
1998     return 0;
1999 }