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