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