]> code.delx.au - pulseaudio/blob - src/cli.c
add dependency script
[pulseaudio] / src / cli.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <assert.h>
4 #include <stdlib.h>
5
6 #include "ioline.h"
7 #include "cli.h"
8 #include "module.h"
9 #include "sink.h"
10 #include "source.h"
11 #include "client.h"
12 #include "sinkinput.h"
13 #include "sourceoutput.h"
14 #include "tokenizer.h"
15 #include "strbuf.h"
16 #include "namereg.h"
17 #include "clitext.h"
18
19 struct pa_cli {
20 struct pa_core *core;
21 struct pa_ioline *line;
22
23 void (*eof_callback)(struct pa_cli *c, void *userdata);
24 void *userdata;
25
26 struct pa_client *client;
27 };
28
29 struct command {
30 const char *name;
31 int (*proc) (struct pa_cli *cli, struct pa_tokenizer*t);
32 const char *help;
33 unsigned args;
34 };
35
36 static void line_callback(struct pa_ioline *line, const char *s, void *userdata);
37
38 static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t);
39 static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t);
40 static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t);
41 static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t);
42 static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t);
43 static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t);
44 static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t);
45 static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t);
46 static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t);
47 static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t);
48 static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t);
49 static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t);
50 static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t);
51 static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t);
52 static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t);
53 static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t);
54 static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t);
55 static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t);
56 static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t);
57
58 static const struct command commands[] = {
59 { "exit", pa_cli_command_exit, "Terminate the daemon", 1 },
60 { "help", pa_cli_command_help, "Show this help", 1 },
61 { "modules", pa_cli_command_modules, "List loaded modules", 1 },
62 { "sinks", pa_cli_command_sinks, "List loaded sinks", 1 },
63 { "sources", pa_cli_command_sources, "List loaded sources", 1 },
64 { "clients", pa_cli_command_clients, "List loaded clients", 1 },
65 { "sink_inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 },
66 { "source_outputs", pa_cli_command_source_outputs, "List source outputs", 1 },
67 { "stat", pa_cli_command_stat, "Show memory block statistics", 1 },
68 { "info", pa_cli_command_info, "Show comprehensive status", 1 },
69 { "ls", pa_cli_command_info, NULL, 1 },
70 { "list", pa_cli_command_info, NULL, 1 },
71 { "load", pa_cli_command_load, "Load a module (args: name, arguments)", 3},
72 { "unload", pa_cli_command_unload, "Unload a module (args: index)", 2},
73 { "sink_volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3},
74 { "sink_input_volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3},
75 { "sink_default", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2},
76 { "source_default", pa_cli_command_source_default, "Set the default source (args: index|name)", 2},
77 { "kill_client", pa_cli_command_kill_client, "Kill a client (args: index)", 2},
78 { "kill_sink_input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2},
79 { "kill_source_output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2},
80 { NULL, NULL, NULL, 0 }
81 };
82
83 static const char prompt[] = ">>> ";
84
85 static void client_kill(struct pa_client *c);
86
87 struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m) {
88 char cname[256];
89 struct pa_cli *c;
90 assert(io);
91
92 c = malloc(sizeof(struct pa_cli));
93 assert(c);
94 c->core = core;
95 c->line = pa_ioline_new(io);
96 assert(c->line);
97
98 c->userdata = NULL;
99 c->eof_callback = NULL;
100
101 pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
102 c->client = pa_client_new(core, "CLI", cname);
103 assert(c->client);
104 c->client->kill = client_kill;
105 c->client->userdata = c;
106 c->client->owner = m;
107
108 pa_ioline_set_callback(c->line, line_callback, c);
109 pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n");
110 pa_ioline_puts(c->line, prompt);
111
112 return c;
113 }
114
115 void pa_cli_free(struct pa_cli *c) {
116 assert(c);
117 pa_ioline_free(c->line);
118 pa_client_free(c->client);
119 free(c);
120 }
121
122 static void client_kill(struct pa_client *client) {
123 struct pa_cli *c;
124 assert(client && client->userdata);
125 c = client->userdata;
126 fprintf(stderr, "CLI client killed.\n");
127
128 if (c->eof_callback)
129 c->eof_callback(c, c->userdata);
130 }
131
132 static void line_callback(struct pa_ioline *line, const char *s, void *userdata) {
133 struct pa_cli *c = userdata;
134 const char *cs;
135 const char delimiter[] = " \t\n\r";
136 assert(line && c);
137
138 if (!s) {
139 fprintf(stderr, "CLI got EOF from user.\n");
140 if (c->eof_callback)
141 c->eof_callback(c, c->userdata);
142
143 return;
144 }
145
146 cs = s+strspn(s, delimiter);
147 if (*cs && *cs != '#') {
148 const struct command*command;
149 int unknown = 1;
150 size_t l;
151
152 l = strcspn(s, delimiter);
153
154 for (command = commands; command->name; command++)
155 if (strlen(command->name) == l && !strncmp(s, command->name, l)) {
156 int ret;
157 struct pa_tokenizer *t = pa_tokenizer_new(s, command->args);
158 assert(t);
159 ret = command->proc(c, t);
160 pa_tokenizer_free(t);
161 unknown = 0;
162
163 /* A negative return value denotes that the cli object is probably invalid now */
164 if (ret < 0)
165 return;
166 break;
167 }
168
169 if (unknown)
170 pa_ioline_puts(line, "Unknown command\n");
171 }
172
173 pa_ioline_puts(line, prompt);
174 }
175
176 void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void *userdata), void *userdata) {
177 assert(c && cb);
178 c->eof_callback = cb;
179 c->userdata = userdata;
180 }
181
182 static uint32_t parse_index(const char *n) {
183 long index;
184 char *x;
185 index = strtol(n, &x, 0);
186 if (!x || *x != 0 || index < 0)
187 return (uint32_t) PA_IDXSET_INVALID;
188
189 return (uint32_t) index;
190 }
191
192 static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t) {
193 assert(c && c->core && c->core->mainloop && t);
194 c->core->mainloop->quit(c->core->mainloop, 0);
195 return 0;
196 }
197
198 static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) {
199 const struct command*command;
200 struct pa_strbuf *pa_strbuf;
201 char *p;
202 assert(c && t);
203
204 pa_strbuf = pa_strbuf_new();
205 assert(pa_strbuf);
206
207 pa_strbuf_puts(pa_strbuf, "Available commands:\n");
208
209 for (command = commands; command->name; command++)
210 if (command->help)
211 pa_strbuf_printf(pa_strbuf, " %-20s %s\n", command->name, command->help);
212
213 pa_ioline_puts(c->line, p = pa_strbuf_tostring_free(pa_strbuf));
214 free(p);
215 return 0;
216 }
217
218 static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) {
219 char *s;
220 assert(c && t);
221 s = pa_module_list_to_string(c->core);
222 assert(s);
223 pa_ioline_puts(c->line, s);
224 free(s);
225 return 0;
226 }
227
228 static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) {
229 char *s;
230 assert(c && t);
231 s = pa_client_list_to_string(c->core);
232 assert(s);
233 pa_ioline_puts(c->line, s);
234 free(s);
235 return 0;
236 }
237
238 static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) {
239 char *s;
240 assert(c && t);
241 s = pa_sink_list_to_string(c->core);
242 assert(s);
243 pa_ioline_puts(c->line, s);
244 free(s);
245 return 0;
246 }
247
248 static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) {
249 char *s;
250 assert(c && t);
251 s = pa_source_list_to_string(c->core);
252 assert(s);
253 pa_ioline_puts(c->line, s);
254 free(s);
255 return 0;
256 }
257
258 static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) {
259 char *s;
260 assert(c && t);
261 s = pa_sink_input_list_to_string(c->core);
262 assert(s);
263 pa_ioline_puts(c->line, s);
264 free(s);
265 return 0;
266 }
267
268 static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) {
269 char *s;
270 assert(c && t);
271 s = pa_source_output_list_to_string(c->core);
272 assert(s);
273 pa_ioline_puts(c->line, s);
274 free(s);
275 return 0;
276 }
277
278 static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t) {
279 char txt[256];
280 assert(c && t);
281 snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count, pa_memblock_total);
282 pa_ioline_puts(c->line, txt);
283 return 0;
284 }
285
286 static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t) {
287 assert(c && t);
288 pa_cli_command_stat(c, t);
289 pa_cli_command_modules(c, t);
290 pa_cli_command_sinks(c, t);
291 pa_cli_command_sources(c, t);
292 pa_cli_command_clients(c, t);
293 pa_cli_command_sink_inputs(c, t);
294 pa_cli_command_source_outputs(c, t);
295 return 0;
296 }
297
298 static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) {
299 struct pa_module *m;
300 const char *name;
301 char txt[256];
302 assert(c && t);
303
304 if (!(name = pa_tokenizer_get(t, 1))) {
305 pa_ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n");
306 return 0;
307 }
308
309 if (!(m = pa_module_load(c->core, name, pa_tokenizer_get(t, 2)))) {
310 pa_ioline_puts(c->line, "Module load failed.\n");
311 return 0;
312 }
313
314 snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index);
315 pa_ioline_puts(c->line, txt);
316 return 0;
317 }
318
319 static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
320 struct pa_module *m;
321 uint32_t index;
322 const char *i;
323 char *e;
324 assert(c && t);
325
326 if (!(i = pa_tokenizer_get(t, 1))) {
327 pa_ioline_puts(c->line, "You need to specfiy the module index.\n");
328 return 0;
329 }
330
331 index = (uint32_t) strtoul(i, &e, 10);
332 if (*e || !(m = pa_idxset_get_by_index(c->core->modules, index))) {
333 pa_ioline_puts(c->line, "Invalid module index.\n");
334 return 0;
335 }
336
337 pa_module_unload_request(c->core, m);
338 return 0;
339 }
340
341 static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) {
342 const char *n, *v;
343 char *x = NULL;
344 struct pa_sink *sink;
345 long volume;
346
347 if (!(n = pa_tokenizer_get(t, 1))) {
348 pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n");
349 return 0;
350 }
351
352 if (!(v = pa_tokenizer_get(t, 2))) {
353 pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
354 return 0;
355 }
356
357 volume = strtol(v, &x, 0);
358 if (!x || *x != 0 || volume < 0) {
359 pa_ioline_puts(c->line, "Failed to parse volume.\n");
360 return 0;
361 }
362
363 if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) {
364 pa_ioline_puts(c->line, "No sink found by this name or index.\n");
365 return 0;
366 }
367
368 sink->volume = (uint32_t) volume;
369 return 0;
370 }
371
372 static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t) {
373 const char *n, *v;
374 struct pa_sink_input *si;
375 long volume;
376 uint32_t index;
377 char *x;
378
379 if (!(n = pa_tokenizer_get(t, 1))) {
380 pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n");
381 return 0;
382 }
383
384 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
385 pa_ioline_puts(c->line, "Failed to parse index.\n");
386 return 0;
387 }
388
389 if (!(v = pa_tokenizer_get(t, 2))) {
390 pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
391 return 0;
392 }
393
394 x = NULL;
395 volume = strtol(v, &x, 0);
396 if (!x || *x != 0 || volume < 0) {
397 pa_ioline_puts(c->line, "Failed to parse volume.\n");
398 return 0;
399 }
400
401 if (!(si = pa_idxset_get_by_index(c->core->sink_inputs, (uint32_t) index))) {
402 pa_ioline_puts(c->line, "No sink input found with this index.\n");
403 return 0;
404 }
405
406 si->volume = (uint32_t) volume;
407 return 0;
408 }
409
410 static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t) {
411 const char *n;
412 struct pa_sink *sink;
413 assert(c && t);
414
415 if (!(n = pa_tokenizer_get(t, 1))) {
416 pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n");
417 return 0;
418 }
419
420 if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) {
421 pa_ioline_puts(c->line, "No sink found by this name or index.\n");
422 return 0;
423 }
424
425 c->core->default_sink_index = sink->index;
426 return 0;
427 }
428
429 static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t) {
430 const char *n;
431 struct pa_source *source;
432 assert(c && t);
433
434 if (!(n = pa_tokenizer_get(t, 1))) {
435 pa_ioline_puts(c->line, "You need to specify a source either by its name or its index.\n");
436 return 0;
437 }
438
439 if (!(source = pa_namereg_get(c->core, n, PA_NAMEREG_SOURCE))) {
440 pa_ioline_puts(c->line, "No source found by this name or index.\n");
441 return 0;
442 }
443
444 c->core->default_source_index = source->index;
445 return 0;
446 }
447
448 static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t) {
449 const char *n;
450 struct pa_client *client;
451 uint32_t index;
452 int ret;
453 assert(c && t);
454
455 if (!(n = pa_tokenizer_get(t, 1))) {
456 pa_ioline_puts(c->line, "You need to specify a client by its index.\n");
457 return 0;
458 }
459
460 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
461 pa_ioline_puts(c->line, "Failed to parse index.\n");
462 return 0;
463 }
464
465 if (!(client = pa_idxset_get_by_index(c->core->clients, index))) {
466 pa_ioline_puts(c->line, "No client found by this index.\n");
467 return 0;
468 }
469
470 ret = (client->userdata == c) ? -1 : 0;
471 pa_client_kill(client);
472 return ret;
473 }
474
475 static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t) {
476 const char *n;
477 struct pa_sink_input *sink_input;
478 uint32_t index;
479 assert(c && t);
480
481 if (!(n = pa_tokenizer_get(t, 1))) {
482 pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n");
483 return 0;
484 }
485
486 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
487 pa_ioline_puts(c->line, "Failed to parse index.\n");
488 return 0;
489 }
490
491 if (!(sink_input = pa_idxset_get_by_index(c->core->sink_inputs, index))) {
492 pa_ioline_puts(c->line, "No sink input found by this index.\n");
493 return 0;
494 }
495
496 pa_sink_input_kill(sink_input);
497 return 0;
498 }
499
500 static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t) {
501 const char *n;
502 struct pa_source_output *source_output;
503 uint32_t index;
504 assert(c && t);
505
506 if (!(n = pa_tokenizer_get(t, 1))) {
507 pa_ioline_puts(c->line, "You need to specify a source output by its index.\n");
508 return 0;
509 }
510
511 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
512 pa_ioline_puts(c->line, "Failed to parse index.\n");
513 return 0;
514 }
515
516 if (!(source_output = pa_idxset_get_by_index(c->core->source_outputs, index))) {
517 pa_ioline_puts(c->line, "No source output found by this index.\n");
518 return 0;
519 }
520
521 pa_source_output_kill(source_output);
522 return 0;
523 }