Add copyright notices to all relevant files. (based on svn log)
[profile/ivi/pulseaudio.git] / src / pulsecore / cli-command.c
1 /* $Id$ */
2
3 /***
4   This file is part of PulseAudio.
5
6   Copyright 2004-2006 Lennart Poettering
7   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
8
9   PulseAudio is free software; you can redistribute it and/or modify
10   it under the terms of the GNU Lesser General Public License as published
11   by the Free Software Foundation; either version 2 of the License,
12   or (at your option) any later version.
13
14   PulseAudio is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with PulseAudio; if not, write to the Free Software
21   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22   USA.
23 ***/
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <stdlib.h>
33 #include <errno.h>
34
35 #include <pulse/xmalloc.h>
36
37 #include <pulsecore/module.h>
38 #include <pulsecore/sink.h>
39 #include <pulsecore/source.h>
40 #include <pulsecore/client.h>
41 #include <pulsecore/sink-input.h>
42 #include <pulsecore/source-output.h>
43 #include <pulsecore/tokenizer.h>
44 #include <pulsecore/strbuf.h>
45 #include <pulsecore/namereg.h>
46 #include <pulsecore/cli-text.h>
47 #include <pulsecore/core-scache.h>
48 #include <pulsecore/sample-util.h>
49 #include <pulsecore/sound-file.h>
50 #include <pulsecore/play-memchunk.h>
51 #include <pulsecore/autoload.h>
52 #include <pulsecore/sound-file-stream.h>
53 #include <pulsecore/props.h>
54 #include <pulsecore/core-util.h>
55 #include <pulsecore/core-error.h>
56
57 #include "cli-command.h"
58
59 struct command {
60     const char *name;
61     int (*proc) (pa_core *c, pa_tokenizer*t, pa_strbuf *buf, int *fail);
62     const char *help;
63     unsigned args;
64 };
65
66 #define INCLUDE_META ".include"
67 #define FAIL_META ".fail"
68 #define NOFAIL_META ".nofail"
69
70 /* Prototypes for all available commands */
71 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
72 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
73 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
74 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
75 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
76 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
77 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
78 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
79 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
80 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
81 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
82 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
83 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
84 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
85 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
86 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
87 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
88 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
89 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
90 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
91 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
92 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
93 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
94 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
95 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
96 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
97 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
98 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
99 static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
100 static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
101 static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
102 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
103 static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
104 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
105 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
106 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail);
107
108 /* A method table for all available commands */
109
110 static const struct command commands[] = {
111     { "exit",                    pa_cli_command_exit,               "Terminate the daemon",         1 },
112     { "help",                    pa_cli_command_help,               "Show this help",               1 },
113     { "list-modules",            pa_cli_command_modules,            "List loaded modules",          1 },
114     { "list-sinks",              pa_cli_command_sinks,              "List loaded sinks",            1 },
115     { "list-sources",            pa_cli_command_sources,            "List loaded sources",          1 },
116     { "list-clients",            pa_cli_command_clients,            "List loaded clients",          1 },
117     { "list-sink-inputs",        pa_cli_command_sink_inputs,        "List sink inputs",             1 },
118     { "list-source-outputs",     pa_cli_command_source_outputs,     "List source outputs",          1 },
119     { "stat",                    pa_cli_command_stat,               "Show memory block statistics", 1 },
120     { "info",                    pa_cli_command_info,               "Show comprehensive status",    1 },
121     { "ls",                      pa_cli_command_info,               NULL,                           1 },
122     { "list",                    pa_cli_command_info,               NULL,                           1 },
123     { "load-module",             pa_cli_command_load,               "Load a module (args: name, arguments)",                     3},
124     { "unload-module",           pa_cli_command_unload,             "Unload a module (args: index)",                             2},
125     { "set-sink-volume",         pa_cli_command_sink_volume,        "Set the volume of a sink (args: index|name, volume)",             3},
126     { "set-sink-input-volume",   pa_cli_command_sink_input_volume,  "Set the volume of a sink input (args: index|name, volume)", 3},
127     { "set-source-volume",       pa_cli_command_source_volume,      "Set the volume of a source (args: index|name, volume)", 3},
128     { "set-sink-mute",           pa_cli_command_sink_mute,          "Set the mute switch of a sink (args: index|name, mute)", 3},
129     { "set-source-mute",         pa_cli_command_source_mute,        "Set the mute switch of a source (args: index|name, mute)", 3},
130     { "set-default-sink",        pa_cli_command_sink_default,       "Set the default sink (args: index|name)", 2},
131     { "set-default-source",      pa_cli_command_source_default,     "Set the default source (args: index|name)", 2},
132     { "kill-client",             pa_cli_command_kill_client,        "Kill a client (args: index)", 2},
133     { "kill-sink-input",         pa_cli_command_kill_sink_input,    "Kill a sink input (args: index)", 2},
134     { "kill-source-output",      pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
135     { "list-samples",            pa_cli_command_scache_list,        "List all entries in the sample cache", 1},
136     { "play-sample",             pa_cli_command_scache_play,        "Play a sample from the sample cache (args: name, sink|index)", 3},
137     { "remove-sample",           pa_cli_command_scache_remove,      "Remove a sample from the sample cache (args: name)", 2},
138     { "load-sample",             pa_cli_command_scache_load,        "Load a sound file into the sample cache (args: name, filename)", 3},
139     { "load-sample-lazy",        pa_cli_command_scache_load,        "Lazily load a sound file into the sample cache (args: name, filename)", 3},
140     { "load-sample-dir-lazy",    pa_cli_command_scache_load_dir,    "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
141     { "play-file",               pa_cli_command_play_file,          "Play a sound file (args: filename, sink|index)", 3},
142     { "list-autoload",           pa_cli_command_autoload_list,      "List autoload entries", 1},
143     { "add-autoload-sink",       pa_cli_command_autoload_add,       "Add autoload entry for a sink (args: sink, module name, arguments)", 4},
144     { "add-autoload-source",     pa_cli_command_autoload_add,       "Add autoload entry for a source (args: source, module name, arguments)", 4},
145     { "remove-autoload-sink",    pa_cli_command_autoload_remove,    "Remove autoload entry for a sink (args: name)", 2},
146     { "remove-autoload-source",  pa_cli_command_autoload_remove,    "Remove autoload entry for a source (args: name)", 2},
147     { "dump",                    pa_cli_command_dump,               "Dump daemon configuration", 1},
148     { "list-props",              pa_cli_command_list_props,         NULL, 1},
149     { "move-sink-input",         pa_cli_command_move_sink_input,    "Move sink input to another sink (args: index, sink)", 3},
150     { "move-source-output",      pa_cli_command_move_source_output, "Move source output to another source (args: index, source)", 3},
151     { "vacuum",                  pa_cli_command_vacuum,             NULL, 1},
152     { NULL, NULL, NULL, 0 }
153 };
154
155 static const char whitespace[] = " \t\n\r";
156 static const char linebreak[] = "\n\r";
157
158 static uint32_t parse_index(const char *n) {
159     uint32_t idx;
160
161     if (pa_atou(n, &idx) < 0)
162         return (uint32_t) PA_IDXSET_INVALID;
163
164     return idx;
165 }
166
167 static int pa_cli_command_exit(pa_core *c, pa_tokenizer *t, PA_GCC_UNUSED pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
168     assert(c && c->mainloop && t);
169     c->mainloop->quit(c->mainloop, 0);
170     return 0;
171 }
172
173 static int pa_cli_command_help(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
174     const struct command*command;
175     assert(c && t && buf);
176
177     pa_strbuf_puts(buf, "Available commands:\n");
178
179     for (command = commands; command->name; command++)
180         if (command->help)
181             pa_strbuf_printf(buf, "    %-25s %s\n", command->name, command->help);
182     return 0;
183 }
184
185 static int pa_cli_command_modules(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
186     char *s;
187     assert(c && t);
188     s = pa_module_list_to_string(c);
189     assert(s);
190     pa_strbuf_puts(buf, s);
191     pa_xfree(s);
192     return 0;
193 }
194
195 static int pa_cli_command_clients(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
196     char *s;
197     assert(c && t);
198     s = pa_client_list_to_string(c);
199     assert(s);
200     pa_strbuf_puts(buf, s);
201     pa_xfree(s);
202     return 0;
203 }
204
205 static int pa_cli_command_sinks(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
206     char *s;
207     assert(c && t);
208     s = pa_sink_list_to_string(c);
209     assert(s);
210     pa_strbuf_puts(buf, s);
211     pa_xfree(s);
212     return 0;
213 }
214
215 static int pa_cli_command_sources(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
216     char *s;
217     assert(c && t);
218     s = pa_source_list_to_string(c);
219     assert(s);
220     pa_strbuf_puts(buf, s);
221     pa_xfree(s);
222     return 0;
223 }
224
225 static int pa_cli_command_sink_inputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
226     char *s;
227     assert(c && t);
228     s = pa_sink_input_list_to_string(c);
229     assert(s);
230     pa_strbuf_puts(buf, s);
231     pa_xfree(s);
232     return 0;
233 }
234
235 static int pa_cli_command_source_outputs(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
236     char *s;
237     assert(c && t);
238     s = pa_source_output_list_to_string(c);
239     assert(s);
240     pa_strbuf_puts(buf, s);
241     pa_xfree(s);
242     return 0;
243 }
244
245 static int pa_cli_command_stat(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
246     char s[256];
247     const pa_mempool_stat *stat;
248     unsigned k;
249
250     static const char* const type_table[PA_MEMBLOCK_TYPE_MAX] = {
251         [PA_MEMBLOCK_POOL] = "POOL",
252         [PA_MEMBLOCK_POOL_EXTERNAL] = "POOL_EXTERNAL",
253         [PA_MEMBLOCK_APPENDED] = "APPENDED",
254         [PA_MEMBLOCK_USER] = "USER",
255         [PA_MEMBLOCK_FIXED] = "FIXED",
256         [PA_MEMBLOCK_IMPORTED] = "IMPORTED",
257     };
258
259     assert(c);
260     assert(t);
261
262     stat = pa_mempool_get_stat(c->mempool);
263
264     pa_strbuf_printf(buf, "Memory blocks currently allocated: %u, size: %s.\n",
265                      (unsigned) AO_load_acquire_read((AO_t*) &stat->n_allocated),
266                      pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->allocated_size)));
267
268     pa_strbuf_printf(buf, "Memory blocks allocated during the whole lifetime: %u, size: %s.\n",
269                      (unsigned) AO_load_acquire_read((AO_t*) &stat->n_accumulated),
270                      pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->accumulated_size)));
271
272     pa_strbuf_printf(buf, "Memory blocks imported from other processes: %u, size: %s.\n",
273                      (unsigned) AO_load_acquire_read((AO_t*) &stat->n_imported),
274                      pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->imported_size)));
275
276     pa_strbuf_printf(buf, "Memory blocks exported to other processes: %u, size: %s.\n",
277                      (unsigned) AO_load_acquire_read((AO_t*) &stat->n_exported),
278                      pa_bytes_snprint(s, sizeof(s), (size_t) AO_load_acquire_read((AO_t*) &stat->exported_size)));
279
280     pa_strbuf_printf(buf, "Total sample cache size: %s.\n",
281                      pa_bytes_snprint(s, sizeof(s), pa_scache_total_size(c)));
282
283     pa_strbuf_printf(buf, "Default sample spec: %s\n",
284                      pa_sample_spec_snprint(s, sizeof(s), &c->default_sample_spec));
285
286     pa_strbuf_printf(buf, "Default sink name: %s\n"
287                      "Default source name: %s\n",
288                      pa_namereg_get_default_sink_name(c),
289                      pa_namereg_get_default_source_name(c));
290
291     for (k = 0; k < PA_MEMBLOCK_TYPE_MAX; k++)
292         pa_strbuf_printf(buf,
293                          "Memory blocks of type %s: %u allocated/%u accumulated.\n",
294                          type_table[k],
295                          (unsigned) AO_load_acquire_read(&stat->n_allocated_by_type[k]),
296                          (unsigned) AO_load_acquire_read(&stat->n_accumulated_by_type[k]));
297
298     return 0;
299 }
300
301 static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
302     assert(c && t);
303     pa_cli_command_stat(c, t, buf, fail);
304     pa_cli_command_modules(c, t, buf, fail);
305     pa_cli_command_sinks(c, t, buf, fail);
306     pa_cli_command_sources(c, t, buf, fail);
307     pa_cli_command_clients(c, t, buf, fail);
308     pa_cli_command_sink_inputs(c, t, buf, fail);
309     pa_cli_command_source_outputs(c, t, buf, fail);
310     pa_cli_command_scache_list(c, t, buf, fail);
311     pa_cli_command_autoload_list(c, t, buf, fail);
312     return 0;
313 }
314
315 static int pa_cli_command_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
316     pa_module *m;
317     const char *name;
318     assert(c && t);
319
320     if (!(name = pa_tokenizer_get(t, 1))) {
321         pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n");
322         return -1;
323     }
324
325     if (!(m = pa_module_load(c, name,  pa_tokenizer_get(t, 2)))) {
326         pa_strbuf_puts(buf, "Module load failed.\n");
327         return -1;
328     }
329
330     return 0;
331 }
332
333 static int pa_cli_command_unload(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
334     pa_module *m;
335     uint32_t idx;
336     const char *i;
337     char *e;
338     assert(c && t);
339
340     if (!(i = pa_tokenizer_get(t, 1))) {
341         pa_strbuf_puts(buf, "You need to specify the module index.\n");
342         return -1;
343     }
344
345     idx = (uint32_t) strtoul(i, &e, 10);
346     if (*e || !(m = pa_idxset_get_by_index(c->modules, idx))) {
347         pa_strbuf_puts(buf, "Invalid module index.\n");
348         return -1;
349     }
350
351     pa_module_unload_request(m);
352     return 0;
353 }
354
355 static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
356     const char *n, *v;
357     pa_sink *sink;
358     uint32_t volume;
359     pa_cvolume cvolume;
360
361     if (!(n = pa_tokenizer_get(t, 1))) {
362         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
363         return -1;
364     }
365
366     if (!(v = pa_tokenizer_get(t, 2))) {
367         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
368         return -1;
369     }
370
371     if (pa_atou(v, &volume) < 0) {
372         pa_strbuf_puts(buf, "Failed to parse volume.\n");
373         return -1;
374     }
375
376     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
377         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
378         return -1;
379     }
380
381     pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
382     pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume);
383     return 0;
384 }
385
386 static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
387     const char *n, *v;
388     pa_sink_input *si;
389     pa_volume_t volume;
390     pa_cvolume cvolume;
391     uint32_t idx;
392
393     if (!(n = pa_tokenizer_get(t, 1))) {
394         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
395         return -1;
396     }
397
398     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
399         pa_strbuf_puts(buf, "Failed to parse index.\n");
400         return -1;
401     }
402
403     if (!(v = pa_tokenizer_get(t, 2))) {
404         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
405         return -1;
406     }
407
408     if (pa_atou(v, &volume) < 0) {
409         pa_strbuf_puts(buf, "Failed to parse volume.\n");
410         return -1;
411     }
412
413     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
414         pa_strbuf_puts(buf, "No sink input found with this index.\n");
415         return -1;
416     }
417
418     pa_cvolume_set(&cvolume, si->sample_spec.channels, volume);
419     pa_sink_input_set_volume(si, &cvolume);
420     return 0;
421 }
422
423 static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
424     const char *n, *v;
425     pa_source *source;
426     uint32_t volume;
427     pa_cvolume cvolume;
428
429     if (!(n = pa_tokenizer_get(t, 1))) {
430         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
431         return -1;
432     }
433
434     if (!(v = pa_tokenizer_get(t, 2))) {
435         pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
436         return -1;
437     }
438
439     if (pa_atou(v, &volume) < 0) {
440         pa_strbuf_puts(buf, "Failed to parse volume.\n");
441         return -1;
442     }
443
444     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
445         pa_strbuf_puts(buf, "No source found by this name or index.\n");
446         return -1;
447     }
448
449     pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
450     pa_source_set_volume(source, PA_MIXER_HARDWARE, &cvolume);
451     return 0;
452 }
453
454 static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
455     const char *n, *m;
456     pa_sink *sink;
457     int mute;
458
459     if (!(n = pa_tokenizer_get(t, 1))) {
460         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
461         return -1;
462     }
463
464     if (!(m = pa_tokenizer_get(t, 2))) {
465         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
466         return -1;
467     }
468
469     if (pa_atoi(m, &mute) < 0) {
470         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
471         return -1;
472     }
473
474     if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK, 1))) {
475         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
476         return -1;
477     }
478
479     pa_sink_set_mute(sink, PA_MIXER_HARDWARE, mute);
480     return 0;
481 }
482
483 static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
484     const char *n, *m;
485     pa_source *source;
486     int mute;
487
488     if (!(n = pa_tokenizer_get(t, 1))) {
489         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
490         return -1;
491     }
492
493     if (!(m = pa_tokenizer_get(t, 2))) {
494         pa_strbuf_puts(buf, "You need to specify a mute switch setting (0/1).\n");
495         return -1;
496     }
497
498     if (pa_atoi(m, &mute) < 0) {
499         pa_strbuf_puts(buf, "Failed to parse mute switch.\n");
500         return -1;
501     }
502
503     if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE, 1))) {
504         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
505         return -1;
506     }
507
508     pa_source_set_mute(source, PA_MIXER_HARDWARE, mute);
509     return 0;
510 }
511
512 static int pa_cli_command_sink_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
513     const char *n;
514     assert(c && t);
515
516     if (!(n = pa_tokenizer_get(t, 1))) {
517         pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
518         return -1;
519     }
520
521     pa_namereg_set_default(c, n, PA_NAMEREG_SINK);
522     return 0;
523 }
524
525 static int pa_cli_command_source_default(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
526     const char *n;
527     assert(c && t);
528
529     if (!(n = pa_tokenizer_get(t, 1))) {
530         pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
531         return -1;
532     }
533
534     pa_namereg_set_default(c, n, PA_NAMEREG_SOURCE);
535     return 0;
536 }
537
538 static int pa_cli_command_kill_client(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
539     const char *n;
540     pa_client *client;
541     uint32_t idx;
542     assert(c && t);
543
544     if (!(n = pa_tokenizer_get(t, 1))) {
545         pa_strbuf_puts(buf, "You need to specify a client by its index.\n");
546         return -1;
547     }
548
549     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
550         pa_strbuf_puts(buf, "Failed to parse index.\n");
551         return -1;
552     }
553
554     if (!(client = pa_idxset_get_by_index(c->clients, idx))) {
555         pa_strbuf_puts(buf, "No client found by this index.\n");
556         return -1;
557     }
558
559     pa_client_kill(client);
560     return 0;
561 }
562
563 static int pa_cli_command_kill_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
564     const char *n;
565     pa_sink_input *sink_input;
566     uint32_t idx;
567     assert(c && t);
568
569     if (!(n = pa_tokenizer_get(t, 1))) {
570         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
571         return -1;
572     }
573
574     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
575         pa_strbuf_puts(buf, "Failed to parse index.\n");
576         return -1;
577     }
578
579     if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, idx))) {
580         pa_strbuf_puts(buf, "No sink input found by this index.\n");
581         return -1;
582     }
583
584     pa_sink_input_kill(sink_input);
585     return 0;
586 }
587
588 static int pa_cli_command_kill_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
589     const char *n;
590     pa_source_output *source_output;
591     uint32_t idx;
592     assert(c && t);
593
594     if (!(n = pa_tokenizer_get(t, 1))) {
595         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
596         return -1;
597     }
598
599     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
600         pa_strbuf_puts(buf, "Failed to parse index.\n");
601         return -1;
602     }
603
604     if (!(source_output = pa_idxset_get_by_index(c->source_outputs, idx))) {
605         pa_strbuf_puts(buf, "No source output found by this index.\n");
606         return -1;
607     }
608
609     pa_source_output_kill(source_output);
610     return 0;
611 }
612
613 static int pa_cli_command_scache_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
614     char *s;
615     assert(c && t);
616     s = pa_scache_list_to_string(c);
617     assert(s);
618     pa_strbuf_puts(buf, s);
619     pa_xfree(s);
620     return 0;
621 }
622
623 static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
624     const char *n, *sink_name;
625     pa_sink *sink;
626     assert(c && t && buf && fail);
627
628     if (!(n = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
629         pa_strbuf_puts(buf, "You need to specify a sample name and a sink name.\n");
630         return -1;
631     }
632
633     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) {
634         pa_strbuf_puts(buf, "No sink by that name.\n");
635         return -1;
636     }
637
638     if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) {
639         pa_strbuf_puts(buf, "Failed to play sample.\n");
640         return -1;
641     }
642
643     return 0;
644 }
645
646 static int pa_cli_command_scache_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
647     const char *n;
648     assert(c && t && buf && fail);
649
650     if (!(n = pa_tokenizer_get(t, 1))) {
651         pa_strbuf_puts(buf, "You need to specify a sample name.\n");
652         return -1;
653     }
654
655     if (pa_scache_remove_item(c, n) < 0) {
656         pa_strbuf_puts(buf, "Failed to remove sample.\n");
657         return -1;
658     }
659
660     return 0;
661 }
662
663 static int pa_cli_command_scache_load(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
664     const char *fname, *n;
665     int r;
666     assert(c && t && buf && fail);
667
668     if (!(fname = pa_tokenizer_get(t, 2)) || !(n = pa_tokenizer_get(t, 1))) {
669         pa_strbuf_puts(buf, "You need to specify a file name and a sample name.\n");
670         return -1;
671     }
672
673     if (strstr(pa_tokenizer_get(t, 0), "lazy"))
674         r = pa_scache_add_file_lazy(c, n, fname, NULL);
675     else
676         r = pa_scache_add_file(c, n, fname, NULL);
677
678     if (r < 0)
679         pa_strbuf_puts(buf, "Failed to load sound file.\n");
680
681     return 0;
682 }
683
684 static int pa_cli_command_scache_load_dir(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
685     const char *pname;
686     assert(c && t && buf && fail);
687
688     if (!(pname = pa_tokenizer_get(t, 1))) {
689         pa_strbuf_puts(buf, "You need to specify a path name.\n");
690         return -1;
691     }
692
693     if (pa_scache_add_directory_lazy(c, pname) < 0) {
694         pa_strbuf_puts(buf, "Failed to load directory.\n");
695         return -1;
696     }
697
698     return 0;
699 }
700
701 static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
702     const char *fname, *sink_name;
703     pa_sink *sink;
704     assert(c && t && buf && fail);
705
706     if (!(fname = pa_tokenizer_get(t, 1)) || !(sink_name = pa_tokenizer_get(t, 2))) {
707         pa_strbuf_puts(buf, "You need to specify a file name and a sink name.\n");
708         return -1;
709     }
710
711     if (!(sink = pa_namereg_get(c, sink_name, PA_NAMEREG_SINK, 1))) {
712         pa_strbuf_puts(buf, "No sink by that name.\n");
713         return -1;
714     }
715
716
717     return pa_play_file(sink, fname, NULL);
718 }
719
720 static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
721     const char *a, *b;
722     assert(c && t && buf && fail);
723
724     if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) {
725         pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
726         return -1;
727     }
728
729     pa_autoload_add(c, a, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, b, pa_tokenizer_get(t, 3), NULL);
730
731     return 0;
732 }
733
734 static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
735     const char *name;
736     assert(c && t && buf && fail);
737
738     if (!(name = pa_tokenizer_get(t, 1))) {
739         pa_strbuf_puts(buf, "You need to specify a device name\n");
740         return -1;
741     }
742
743     if (pa_autoload_remove_by_name(c, name, strstr(pa_tokenizer_get(t, 0), "sink") ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE) < 0) {
744         pa_strbuf_puts(buf, "Failed to remove autload entry\n");
745         return -1;
746     }
747
748     return 0;
749 }
750
751 static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
752     char *s;
753     assert(c && t);
754     s = pa_autoload_list_to_string(c);
755     assert(s);
756     pa_strbuf_puts(buf, s);
757     pa_xfree(s);
758     return 0;
759 }
760
761 static int pa_cli_command_list_props(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
762     assert(c && t);
763     pa_property_dump(c, buf);
764     return 0;
765 }
766
767 static int pa_cli_command_vacuum(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
768     assert(c);
769     assert(t);
770
771     pa_mempool_vacuum(c->mempool);
772
773     return 0;
774 }
775
776 static int pa_cli_command_move_sink_input(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
777     const char *n, *k;
778     pa_sink_input *si;
779     pa_sink *sink;
780     uint32_t idx;
781
782     if (!(n = pa_tokenizer_get(t, 1))) {
783         pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n");
784         return -1;
785     }
786
787     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
788         pa_strbuf_puts(buf, "Failed to parse index.\n");
789         return -1;
790     }
791
792     if (!(k = pa_tokenizer_get(t, 2))) {
793         pa_strbuf_puts(buf, "You need to specify a sink.\n");
794         return -1;
795     }
796
797     if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) idx))) {
798         pa_strbuf_puts(buf, "No sink input found with this index.\n");
799         return -1;
800     }
801
802     if (!(sink = pa_namereg_get(c, k, PA_NAMEREG_SINK, 1))) {
803         pa_strbuf_puts(buf, "No sink found by this name or index.\n");
804         return -1;
805     }
806
807     if (pa_sink_input_move_to(si, sink, 0) < 0) {
808         pa_strbuf_puts(buf, "Moved failed.\n");
809         return -1;
810     }
811     return 0;
812 }
813
814 static int pa_cli_command_move_source_output(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) {
815     const char *n, *k;
816     pa_source_output *so;
817     pa_source *source;
818     uint32_t idx;
819
820     if (!(n = pa_tokenizer_get(t, 1))) {
821         pa_strbuf_puts(buf, "You need to specify a source output by its index.\n");
822         return -1;
823     }
824
825     if ((idx = parse_index(n)) == PA_IDXSET_INVALID) {
826         pa_strbuf_puts(buf, "Failed to parse index.\n");
827         return -1;
828     }
829
830     if (!(k = pa_tokenizer_get(t, 2))) {
831         pa_strbuf_puts(buf, "You need to specify a source.\n");
832         return -1;
833     }
834
835     if (!(so = pa_idxset_get_by_index(c->source_outputs, (uint32_t) idx))) {
836         pa_strbuf_puts(buf, "No source output found with this index.\n");
837         return -1;
838     }
839
840     if (!(source = pa_namereg_get(c, k, PA_NAMEREG_SOURCE, 1))) {
841         pa_strbuf_puts(buf, "No source found by this name or index.\n");
842         return -1;
843     }
844
845     if (pa_source_output_move_to(so, source) < 0) {
846         pa_strbuf_puts(buf, "Moved failed.\n");
847         return -1;
848     }
849     return 0;
850 }
851
852 static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) {
853     pa_module *m;
854     pa_sink *sink;
855     pa_source *source;
856     int nl;
857     const char *p;
858     uint32_t idx;
859     char txt[256];
860     time_t now;
861     void *i;
862     pa_autoload_entry *a;
863
864     assert(c && t);
865
866     time(&now);
867
868 #ifdef HAVE_CTIME_R
869     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime_r(&now, txt));
870 #else
871     pa_strbuf_printf(buf, "### Configuration dump generated at %s\n", ctime(&now));
872 #endif
873
874
875     for (m = pa_idxset_first(c->modules, &idx); m; m = pa_idxset_next(c->modules, &idx)) {
876         if (m->auto_unload)
877             continue;
878
879         pa_strbuf_printf(buf, "load-module %s", m->name);
880
881         if (m->argument)
882             pa_strbuf_printf(buf, " %s", m->argument);
883
884         pa_strbuf_puts(buf, "\n");
885     }
886
887     nl = 0;
888
889     for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
890         if (sink->owner && sink->owner->auto_unload)
891             continue;
892
893         if (!nl) {
894             pa_strbuf_puts(buf, "\n");
895             nl = 1;
896         }
897
898         pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", sink->name, pa_cvolume_avg(pa_sink_get_volume(sink, PA_MIXER_HARDWARE)));
899         pa_strbuf_printf(buf, "set-sink-mute %s %d\n", sink->name, pa_sink_get_mute(sink, PA_MIXER_HARDWARE));
900     }
901
902     for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
903         if (source->owner && source->owner->auto_unload)
904             continue;
905
906         if (!nl) {
907             pa_strbuf_puts(buf, "\n");
908             nl = 1;
909         }
910
911         pa_strbuf_printf(buf, "set-source-volume %s 0x%03x\n", source->name, pa_cvolume_avg(pa_source_get_volume(source, PA_MIXER_HARDWARE)));
912         pa_strbuf_printf(buf, "set-source-mute %s %d\n", source->name, pa_source_get_mute(source, PA_MIXER_HARDWARE));
913     }
914
915
916     if (c->autoload_hashmap) {
917         nl = 0;
918
919         i = NULL;
920         while ((a = pa_hashmap_iterate(c->autoload_hashmap, &i, NULL))) {
921
922             if (!nl) {
923                 pa_strbuf_puts(buf, "\n");
924                 nl = 1;
925             }
926
927             pa_strbuf_printf(buf, "add-autoload-%s %s %s", a->type == PA_NAMEREG_SINK ? "sink" : "source", a->name, a->module);
928
929             if (a->argument)
930                 pa_strbuf_printf(buf, " %s", a->argument);
931
932             pa_strbuf_puts(buf, "\n");
933         }
934     }
935
936     nl = 0;
937
938     if ((p = pa_namereg_get_default_sink_name(c))) {
939         if (!nl) {
940             pa_strbuf_puts(buf, "\n");
941             nl = 1;
942         }
943         pa_strbuf_printf(buf, "set-default-sink %s\n", p);
944     }
945
946     if ((p = pa_namereg_get_default_source_name(c))) {
947         if (!nl) {
948             pa_strbuf_puts(buf, "\n");
949             nl = 1;
950         }
951         pa_strbuf_printf(buf, "set-default-source %s\n", p);
952     }
953
954     pa_strbuf_puts(buf, "\n### EOF\n");
955
956     return 0;
957 }
958
959 int pa_cli_command_execute_line(pa_core *c, const char *s, pa_strbuf *buf, int *fail) {
960     const char *cs;
961
962     cs = s+strspn(s, whitespace);
963
964     if (*cs == '#' || !*cs)
965         return 0;
966     else if (*cs == '.') {
967         if (!strcmp(cs, FAIL_META))
968             *fail = 1;
969         else if (!strcmp(cs, NOFAIL_META))
970             *fail = 0;
971         else {
972             size_t l;
973             l = strcspn(cs, whitespace);
974
975             if (l == sizeof(INCLUDE_META)-1 && !strncmp(cs, INCLUDE_META, l)) {
976                 const char *filename = cs+l+strspn(cs+l, whitespace);
977
978                 if (pa_cli_command_execute_file(c, filename, buf, fail) < 0)
979                     if (*fail) return -1;
980             } else {
981                 pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs);
982                 if (*fail) return -1;
983             }
984         }
985     } else {
986         const struct command*command;
987         int unknown = 1;
988         size_t l;
989
990         l = strcspn(cs, whitespace);
991
992         for (command = commands; command->name; command++)
993             if (strlen(command->name) == l && !strncmp(cs, command->name, l)) {
994                 int ret;
995                 pa_tokenizer *t = pa_tokenizer_new(cs, command->args);
996                 assert(t);
997                 ret = command->proc(c, t, buf, fail);
998                 pa_tokenizer_free(t);
999                 unknown = 0;
1000
1001                 if (ret < 0 && *fail)
1002                     return -1;
1003
1004                 break;
1005             }
1006
1007         if (unknown) {
1008             pa_strbuf_printf(buf, "Unknown command: %s\n", cs);
1009             if (*fail)
1010                 return -1;
1011         }
1012     }
1013
1014     return 0;
1015 }
1016
1017 int pa_cli_command_execute_file(pa_core *c, const char *fn, pa_strbuf *buf, int *fail) {
1018     char line[256];
1019     FILE *f = NULL;
1020     int ret = -1;
1021     assert(c && fn && buf);
1022
1023     if (!(f = fopen(fn, "r"))) {
1024         pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, pa_cstrerror(errno));
1025         if (!*fail)
1026             ret = 0;
1027         goto fail;
1028     }
1029
1030     while (fgets(line, sizeof(line), f)) {
1031         char *e = line + strcspn(line, linebreak);
1032         *e = 0;
1033
1034         if (pa_cli_command_execute_line(c, line, buf, fail) < 0 && *fail)
1035             goto fail;
1036     }
1037
1038     ret = 0;
1039
1040 fail:
1041     if (f)
1042         fclose(f);
1043
1044     return ret;
1045 }
1046
1047 int pa_cli_command_execute(pa_core *c, const char *s, pa_strbuf *buf, int *fail) {
1048     const char *p;
1049     assert(c && s && buf && fail);
1050
1051     p = s;
1052     while (*p) {
1053         size_t l = strcspn(p, linebreak);
1054         char *line = pa_xstrndup(p, l);
1055
1056         if (pa_cli_command_execute_line(c, line, buf, fail) < 0&& *fail) {
1057             pa_xfree(line);
1058             return -1;
1059         }
1060         pa_xfree(line);
1061
1062         p += l;
1063         p += strspn(p, linebreak);
1064     }
1065
1066     return 0;
1067 }