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
);