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
) {
91 c
= malloc(sizeof(struct pa_cli
));
94 c
->line
= pa_ioline_new(io
);
98 c
->eof_callback
= NULL
;
100 pa_iochannel_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
;
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
);
113 void pa_cli_free(struct pa_cli
*c
) {
115 pa_ioline_free(c
->line
);
116 pa_client_free(c
->client
);
120 static void client_kill(struct pa_client
*client
) {
122 assert(client
&& client
->userdata
);
123 c
= client
->userdata
;
124 fprintf(stderr
, "CLI client killed.\n");
127 c
->eof_callback(c
, c
->userdata
);
130 static void line_callback(struct pa_ioline
*line
, const char *s
, void *userdata
) {
131 struct pa_cli
*c
= userdata
;
133 const char delimiter
[] = " \t\n\r";
137 fprintf(stderr
, "CLI got EOF from user.\n");
139 c
->eof_callback(c
, c
->userdata
);
144 cs
= s
+strspn(s
, delimiter
);
145 if (*cs
&& *cs
!= '#') {
146 const struct command
*command
;
150 l
= strcspn(s
, delimiter
);
152 for (command
= commands
; command
->name
; command
++)
153 if (strlen(command
->name
) == l
&& !strncmp(s
, command
->name
, l
)) {
155 struct pa_tokenizer
*t
= pa_tokenizer_new(s
, command
->args
);
157 ret
= command
->proc(c
, t
);
158 pa_tokenizer_free(t
);
161 /* A negative return value denotes that the cli object is probably invalid now */
168 pa_ioline_puts(line
, "Unknown command\n");
171 pa_ioline_puts(line
, prompt
);
174 void pa_cli_set_eof_callback(struct pa_cli
*c
, void (*cb
)(struct pa_cli
*c
, void *userdata
), void *userdata
) {
176 c
->eof_callback
= cb
;
177 c
->userdata
= userdata
;
180 static uint32_t parse_index(const char *n
) {
183 index
= strtol(n
, &x
, 0);
184 if (!x
|| *x
!= 0 || index
< 0)
185 return (uint32_t) PA_IDXSET_INVALID
;
187 return (uint32_t) index
;
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);
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
;
202 pa_strbuf
= pa_strbuf_new();
205 pa_strbuf_puts(pa_strbuf
, "Available commands:\n");
207 for (command
= commands
; command
->name
; command
++)
209 pa_strbuf_printf(pa_strbuf
, " %-20s %s\n", command
->name
, command
->help
);
211 pa_ioline_puts(c
->line
, p
= pa_strbuf_tostring_free(pa_strbuf
));
216 static int pa_cli_command_modules(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
219 s
= pa_module_list_to_string(c
->core
);
221 pa_ioline_puts(c
->line
, s
);
226 static int pa_cli_command_clients(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
229 s
= pa_client_list_to_string(c
->core
);
231 pa_ioline_puts(c
->line
, s
);
236 static int pa_cli_command_sinks(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
239 s
= pa_sink_list_to_string(c
->core
);
241 pa_ioline_puts(c
->line
, s
);
246 static int pa_cli_command_sources(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
249 s
= pa_source_list_to_string(c
->core
);
251 pa_ioline_puts(c
->line
, s
);
256 static int pa_cli_command_sink_inputs(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
259 s
= pa_sink_input_list_to_string(c
->core
);
261 pa_ioline_puts(c
->line
, s
);
266 static int pa_cli_command_source_outputs(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
269 s
= pa_source_output_list_to_string(c
->core
);
271 pa_ioline_puts(c
->line
, s
);
276 static int pa_cli_command_stat(struct pa_cli
*c
, struct pa_tokenizer
*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
);
284 static int pa_cli_command_info(struct pa_cli
*c
, struct pa_tokenizer
*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
);
296 static int pa_cli_command_load(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
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");
307 if (!(m
= pa_module_load(c
->core
, name
, pa_tokenizer_get(t
, 2)))) {
308 pa_ioline_puts(c
->line
, "Module load failed.\n");
312 snprintf(txt
, sizeof(txt
), "Module successfully loaded, index: %u.\n", m
->index
);
313 pa_ioline_puts(c
->line
, txt
);
317 static int pa_cli_command_unload(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
324 if (!(i
= pa_tokenizer_get(t
, 1))) {
325 pa_ioline_puts(c
->line
, "You need to specfiy the module index.\n");
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");
335 pa_module_unload_request(c
->core
, m
);
339 static int pa_cli_command_sink_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
342 struct pa_sink
*sink
;
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");
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");
355 volume
= strtol(v
, &x
, 0);
356 if (!x
|| *x
!= 0 || volume
< 0) {
357 pa_ioline_puts(c
->line
, "Failed to parse volume.\n");
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");
366 sink
->volume
= (uint32_t) volume
;
370 static int pa_cli_command_sink_input_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
372 struct pa_sink_input
*si
;
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");
382 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
383 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
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");
393 volume
= strtol(v
, &x
, 0);
394 if (!x
|| *x
!= 0 || volume
< 0) {
395 pa_ioline_puts(c
->line
, "Failed to parse volume.\n");
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");
404 si
->volume
= (uint32_t) volume
;
408 static int pa_cli_command_sink_default(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
410 struct pa_sink
*sink
;
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");
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");
423 c
->core
->default_sink_index
= sink
->index
;
427 static int pa_cli_command_source_default(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
429 struct pa_source
*source
;
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");
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");
442 c
->core
->default_source_index
= source
->index
;
446 static int pa_cli_command_kill_client(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
448 struct pa_client
*client
;
453 if (!(n
= pa_tokenizer_get(t
, 1))) {
454 pa_ioline_puts(c
->line
, "You need to specify a client by its index.\n");
458 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
459 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
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");
468 ret
= (client
->userdata
== c
) ? -1 : 0;
469 pa_client_kill(client
);
473 static int pa_cli_command_kill_sink_input(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
475 struct pa_sink_input
*sink_input
;
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");
484 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
485 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
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");
494 pa_sink_input_kill(sink_input
);
498 static int pa_cli_command_kill_source_output(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
500 struct pa_source_output
*source_output
;
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");
509 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
510 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
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");
519 pa_source_output_kill(source_output
);