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