12 #include "sinkinput.h"
13 #include "sourceoutput.h"
14 #include "tokenizer.h"
20 struct pa_ioline *line;
22 void (*eof_callback)(struct pa_cli *c, void *userdata);
25 struct pa_client *client;
30 int (*proc) (struct pa_cli *cli, struct pa_tokenizer*t);
35 static void line_callback(struct pa_ioline *line, const char *s, void *userdata);
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);
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 }
82 static const char prompt[] = ">>> ";
84 static void client_kill(struct pa_client *c);
86 struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_module *m) {
91 c = malloc(sizeof(struct pa_cli));
94 c->line = pa_ioline_new(io);
98 c->eof_callback = NULL;
100 pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
101 c->client = pa_client_new(core, "CLI", cname);
103 c->client->kill = client_kill;
104 c->client->userdata = c;
105 c->client->owner = m;
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);
114 void pa_cli_free(struct pa_cli *c) {
116 pa_ioline_free(c->line);
117 pa_client_free(c->client);
121 static void client_kill(struct pa_client *client) {
123 assert(client && client->userdata);
124 c = client->userdata;
125 fprintf(stderr, "CLI client killed.\n");
128 c->eof_callback(c, c->userdata);
131 static void line_callback(struct pa_ioline *line, const char *s, void *userdata) {
132 struct pa_cli *c = userdata;
134 const char delimiter[] = " \t\n\r";
138 fprintf(stderr, "CLI got EOF from user.\n");
140 c->eof_callback(c, c->userdata);
145 cs = s+strspn(s, delimiter);
146 if (*cs && *cs != '#') {
147 const struct command*command;
151 l = strcspn(s, delimiter);
153 for (command = commands; command->name; command++)
154 if (strlen(command->name) == l && !strncmp(s, command->name, l)) {
156 struct pa_tokenizer *t = pa_tokenizer_new(s, command->args);
158 ret = command->proc(c, t);
159 pa_tokenizer_free(t);
162 /* A negative return value denotes that the cli object is probably invalid now */
169 pa_ioline_puts(line, "Unknown command\n");
172 pa_ioline_puts(line, prompt);
175 void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void *userdata), void *userdata) {
177 c->eof_callback = cb;
178 c->userdata = userdata;
181 static uint32_t parse_index(const char *n) {
184 index = strtol(n, &x, 0);
185 if (!x || *x != 0 || index < 0)
186 return (uint32_t) PA_IDXSET_INVALID;
188 return (uint32_t) index;
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);
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;
203 pa_strbuf = pa_strbuf_new();
206 pa_strbuf_puts(pa_strbuf, "Available commands:\n");
208 for (command = commands; command->name; command++)
210 pa_strbuf_printf(pa_strbuf, " %-20s %s\n", command->name, command->help);
212 pa_ioline_puts(c->line, p = pa_strbuf_tostring_free(pa_strbuf));
217 static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) {
220 s = pa_module_list_to_string(c->core);
222 pa_ioline_puts(c->line, s);
227 static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) {
230 s = pa_client_list_to_string(c->core);
232 pa_ioline_puts(c->line, s);
237 static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) {
240 s = pa_sink_list_to_string(c->core);
242 pa_ioline_puts(c->line, s);
247 static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) {
250 s = pa_source_list_to_string(c->core);
252 pa_ioline_puts(c->line, s);
257 static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) {
260 s = pa_sink_input_list_to_string(c->core);
262 pa_ioline_puts(c->line, s);
267 static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) {
270 s = pa_source_output_list_to_string(c->core);
272 pa_ioline_puts(c->line, s);
277 static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *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);
285 static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *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);
297 static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) {
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");
308 if (!(m = pa_module_load(c->core, name, pa_tokenizer_get(t, 2)))) {
309 pa_ioline_puts(c->line, "Module load failed.\n");
313 snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index);
314 pa_ioline_puts(c->line, txt);
318 static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
325 if (!(i = pa_tokenizer_get(t, 1))) {
326 pa_ioline_puts(c->line, "You need to specfiy the module index.\n");
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");
336 pa_module_unload_request(c->core, m);
340 static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) {
343 struct pa_sink *sink;
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");
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");
356 volume = strtol(v, &x, 0);
357 if (!x || *x != 0 || volume < 0) {
358 pa_ioline_puts(c->line, "Failed to parse volume.\n");
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");
367 sink->volume = (uint32_t) volume;
371 static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t) {
373 struct pa_sink_input *si;
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");
383 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
384 pa_ioline_puts(c->line, "Failed to parse index.\n");
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");
394 volume = strtol(v, &x, 0);
395 if (!x || *x != 0 || volume < 0) {
396 pa_ioline_puts(c->line, "Failed to parse volume.\n");
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");
405 si->volume = (uint32_t) volume;
409 static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t) {
411 struct pa_sink *sink;
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");
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");
424 c->core->default_sink_index = sink->index;
428 static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t) {
430 struct pa_source *source;
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");
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");
443 c->core->default_source_index = source->index;
447 static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t) {
449 struct pa_client *client;
454 if (!(n = pa_tokenizer_get(t, 1))) {
455 pa_ioline_puts(c->line, "You need to specify a client by its index.\n");
459 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
460 pa_ioline_puts(c->line, "Failed to parse index.\n");
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");
469 ret = (client->userdata == c) ? -1 : 0;
470 pa_client_kill(client);
474 static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t) {
476 struct pa_sink_input *sink_input;
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");
485 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
486 pa_ioline_puts(c->line, "Failed to parse index.\n");
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");
495 pa_sink_input_kill(sink_input);
499 static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t) {
501 struct pa_source_output *source_output;
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");
510 if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
511 pa_ioline_puts(c->line, "Failed to parse index.\n");
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");
520 pa_source_output_kill(source_output);