12 #include "sinkinput.h"
13 #include "sourceoutput.h"
14 #include "tokenizer.h"
21 struct pa_ioline
*line
;
23 void (*eof_callback
)(struct pa_cli
*c
, void *userdata
);
26 struct pa_client
*client
;
31 int (*proc
) (struct pa_cli
*cli
, struct pa_tokenizer
*t
);
36 static void line_callback(struct pa_ioline
*line
, const char *s
, void *userdata
);
38 static int pa_cli_command_exit(struct pa_cli
*c
, struct pa_tokenizer
*t
);
39 static int pa_cli_command_help(struct pa_cli
*c
, struct pa_tokenizer
*t
);
40 static int pa_cli_command_modules(struct pa_cli
*c
, struct pa_tokenizer
*t
);
41 static int pa_cli_command_clients(struct pa_cli
*c
, struct pa_tokenizer
*t
);
42 static int pa_cli_command_sinks(struct pa_cli
*c
, struct pa_tokenizer
*t
);
43 static int pa_cli_command_sources(struct pa_cli
*c
, struct pa_tokenizer
*t
);
44 static int pa_cli_command_sink_inputs(struct pa_cli
*c
, struct pa_tokenizer
*t
);
45 static int pa_cli_command_source_outputs(struct pa_cli
*c
, struct pa_tokenizer
*t
);
46 static int pa_cli_command_stat(struct pa_cli
*c
, struct pa_tokenizer
*t
);
47 static int pa_cli_command_info(struct pa_cli
*c
, struct pa_tokenizer
*t
);
48 static int pa_cli_command_load(struct pa_cli
*c
, struct pa_tokenizer
*t
);
49 static int pa_cli_command_unload(struct pa_cli
*c
, struct pa_tokenizer
*t
);
50 static int pa_cli_command_sink_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
);
51 static int pa_cli_command_sink_input_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
);
52 static int pa_cli_command_sink_default(struct pa_cli
*c
, struct pa_tokenizer
*t
);
53 static int pa_cli_command_source_default(struct pa_cli
*c
, struct pa_tokenizer
*t
);
54 static int pa_cli_command_kill_client(struct pa_cli
*c
, struct pa_tokenizer
*t
);
55 static int pa_cli_command_kill_sink_input(struct pa_cli
*c
, struct pa_tokenizer
*t
);
56 static int pa_cli_command_kill_source_output(struct pa_cli
*c
, struct pa_tokenizer
*t
);
58 static const struct command commands
[] = {
59 { "exit", pa_cli_command_exit
, "Terminate the daemon", 1 },
60 { "help", pa_cli_command_help
, "Show this help", 1 },
61 { "modules", pa_cli_command_modules
, "List loaded modules", 1 },
62 { "sinks", pa_cli_command_sinks
, "List loaded sinks", 1 },
63 { "sources", pa_cli_command_sources
, "List loaded sources", 1 },
64 { "clients", pa_cli_command_clients
, "List loaded clients", 1 },
65 { "sink_inputs", pa_cli_command_sink_inputs
, "List sink inputs", 1 },
66 { "source_outputs", pa_cli_command_source_outputs
, "List source outputs", 1 },
67 { "stat", pa_cli_command_stat
, "Show memory block statistics", 1 },
68 { "info", pa_cli_command_info
, "Show comprehensive status", 1 },
69 { "ls", pa_cli_command_info
, NULL
, 1 },
70 { "list", pa_cli_command_info
, NULL
, 1 },
71 { "load", pa_cli_command_load
, "Load a module (args: name, arguments)", 3},
72 { "unload", pa_cli_command_unload
, "Unload a module (args: index)", 2},
73 { "sink_volume", pa_cli_command_sink_volume
, "Set the volume of a sink (args: index|name, volume)", 3},
74 { "sink_input_volume", pa_cli_command_sink_input_volume
, "Set the volume of a sink input (args: index|name, volume)", 3},
75 { "sink_default", pa_cli_command_sink_default
, "Set the default sink (args: index|name)", 2},
76 { "source_default", pa_cli_command_source_default
, "Set the default source (args: index|name)", 2},
77 { "kill_client", pa_cli_command_kill_client
, "Kill a client (args: index)", 2},
78 { "kill_sink_input", pa_cli_command_kill_sink_input
, "Kill a sink input (args: index)", 2},
79 { "kill_source_output", pa_cli_command_kill_source_output
, "Kill a source output (args: index)", 2},
80 { NULL
, NULL
, NULL
, 0 }
83 static const char prompt
[] = ">>> ";
85 static void client_kill(struct pa_client
*c
);
87 struct pa_cli
* pa_cli_new(struct pa_core
*core
, struct pa_iochannel
*io
, struct pa_module
*m
) {
92 c
= malloc(sizeof(struct pa_cli
));
95 c
->line
= pa_ioline_new(io
);
99 c
->eof_callback
= NULL
;
101 pa_iochannel_socket_peer_to_string(io
, cname
, sizeof(cname
));
102 c
->client
= pa_client_new(core
, "CLI", cname
);
104 c
->client
->kill
= client_kill
;
105 c
->client
->userdata
= c
;
106 c
->client
->owner
= m
;
108 pa_ioline_set_callback(c
->line
, line_callback
, c
);
109 pa_ioline_puts(c
->line
, "Welcome to polypaudio! Use \"help\" for usage information.\n");
110 pa_ioline_puts(c
->line
, prompt
);
115 void pa_cli_free(struct pa_cli
*c
) {
117 pa_ioline_free(c
->line
);
118 pa_client_free(c
->client
);
122 static void client_kill(struct pa_client
*client
) {
124 assert(client
&& client
->userdata
);
125 c
= client
->userdata
;
126 fprintf(stderr
, "CLI client killed.\n");
129 c
->eof_callback(c
, c
->userdata
);
132 static void line_callback(struct pa_ioline
*line
, const char *s
, void *userdata
) {
133 struct pa_cli
*c
= userdata
;
135 const char delimiter
[] = " \t\n\r";
139 fprintf(stderr
, "CLI got EOF from user.\n");
141 c
->eof_callback(c
, c
->userdata
);
146 cs
= s
+strspn(s
, delimiter
);
147 if (*cs
&& *cs
!= '#') {
148 const struct command
*command
;
152 l
= strcspn(s
, delimiter
);
154 for (command
= commands
; command
->name
; command
++)
155 if (strlen(command
->name
) == l
&& !strncmp(s
, command
->name
, l
)) {
157 struct pa_tokenizer
*t
= pa_tokenizer_new(s
, command
->args
);
159 ret
= command
->proc(c
, t
);
160 pa_tokenizer_free(t
);
163 /* A negative return value denotes that the cli object is probably invalid now */
170 pa_ioline_puts(line
, "Unknown command\n");
173 pa_ioline_puts(line
, prompt
);
176 void pa_cli_set_eof_callback(struct pa_cli
*c
, void (*cb
)(struct pa_cli
*c
, void *userdata
), void *userdata
) {
178 c
->eof_callback
= cb
;
179 c
->userdata
= userdata
;
182 static uint32_t parse_index(const char *n
) {
185 index
= strtol(n
, &x
, 0);
186 if (!x
|| *x
!= 0 || index
< 0)
187 return (uint32_t) PA_IDXSET_INVALID
;
189 return (uint32_t) index
;
192 static int pa_cli_command_exit(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
193 assert(c
&& c
->core
&& c
->core
->mainloop
&& t
);
194 c
->core
->mainloop
->quit(c
->core
->mainloop
, 0);
198 static int pa_cli_command_help(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
199 const struct command
*command
;
200 struct pa_strbuf
*pa_strbuf
;
204 pa_strbuf
= pa_strbuf_new();
207 pa_strbuf_puts(pa_strbuf
, "Available commands:\n");
209 for (command
= commands
; command
->name
; command
++)
211 pa_strbuf_printf(pa_strbuf
, " %-20s %s\n", command
->name
, command
->help
);
213 pa_ioline_puts(c
->line
, p
= pa_strbuf_tostring_free(pa_strbuf
));
218 static int pa_cli_command_modules(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
221 s
= pa_module_list_to_string(c
->core
);
223 pa_ioline_puts(c
->line
, s
);
228 static int pa_cli_command_clients(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
231 s
= pa_client_list_to_string(c
->core
);
233 pa_ioline_puts(c
->line
, s
);
238 static int pa_cli_command_sinks(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
241 s
= pa_sink_list_to_string(c
->core
);
243 pa_ioline_puts(c
->line
, s
);
248 static int pa_cli_command_sources(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
251 s
= pa_source_list_to_string(c
->core
);
253 pa_ioline_puts(c
->line
, s
);
258 static int pa_cli_command_sink_inputs(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
261 s
= pa_sink_input_list_to_string(c
->core
);
263 pa_ioline_puts(c
->line
, s
);
268 static int pa_cli_command_source_outputs(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
271 s
= pa_source_output_list_to_string(c
->core
);
273 pa_ioline_puts(c
->line
, s
);
278 static int pa_cli_command_stat(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
281 snprintf(txt
, sizeof(txt
), "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count
, pa_memblock_total
);
282 pa_ioline_puts(c
->line
, txt
);
286 static int pa_cli_command_info(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
288 pa_cli_command_stat(c
, t
);
289 pa_cli_command_modules(c
, t
);
290 pa_cli_command_sinks(c
, t
);
291 pa_cli_command_sources(c
, t
);
292 pa_cli_command_clients(c
, t
);
293 pa_cli_command_sink_inputs(c
, t
);
294 pa_cli_command_source_outputs(c
, t
);
298 static int pa_cli_command_load(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
304 if (!(name
= pa_tokenizer_get(t
, 1))) {
305 pa_ioline_puts(c
->line
, "You need to specfiy the module name and optionally arguments.\n");
309 if (!(m
= pa_module_load(c
->core
, name
, pa_tokenizer_get(t
, 2)))) {
310 pa_ioline_puts(c
->line
, "Module load failed.\n");
314 snprintf(txt
, sizeof(txt
), "Module successfully loaded, index: %u.\n", m
->index
);
315 pa_ioline_puts(c
->line
, txt
);
319 static int pa_cli_command_unload(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
326 if (!(i
= pa_tokenizer_get(t
, 1))) {
327 pa_ioline_puts(c
->line
, "You need to specfiy the module index.\n");
331 index
= (uint32_t) strtoul(i
, &e
, 10);
332 if (*e
|| !(m
= pa_idxset_get_by_index(c
->core
->modules
, index
))) {
333 pa_ioline_puts(c
->line
, "Invalid module index.\n");
337 pa_module_unload_request(c
->core
, m
);
341 static int pa_cli_command_sink_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
344 struct pa_sink
*sink
;
347 if (!(n
= pa_tokenizer_get(t
, 1))) {
348 pa_ioline_puts(c
->line
, "You need to specify a sink either by its name or its index.\n");
352 if (!(v
= pa_tokenizer_get(t
, 2))) {
353 pa_ioline_puts(c
->line
, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
357 volume
= strtol(v
, &x
, 0);
358 if (!x
|| *x
!= 0 || volume
< 0) {
359 pa_ioline_puts(c
->line
, "Failed to parse volume.\n");
363 if (!(sink
= pa_namereg_get(c
->core
, n
, PA_NAMEREG_SINK
))) {
364 pa_ioline_puts(c
->line
, "No sink found by this name or index.\n");
368 sink
->volume
= (uint32_t) volume
;
372 static int pa_cli_command_sink_input_volume(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
374 struct pa_sink_input
*si
;
379 if (!(n
= pa_tokenizer_get(t
, 1))) {
380 pa_ioline_puts(c
->line
, "You need to specify a sink input by its index.\n");
384 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
385 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
389 if (!(v
= pa_tokenizer_get(t
, 2))) {
390 pa_ioline_puts(c
->line
, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n");
395 volume
= strtol(v
, &x
, 0);
396 if (!x
|| *x
!= 0 || volume
< 0) {
397 pa_ioline_puts(c
->line
, "Failed to parse volume.\n");
401 if (!(si
= pa_idxset_get_by_index(c
->core
->sink_inputs
, (uint32_t) index
))) {
402 pa_ioline_puts(c
->line
, "No sink input found with this index.\n");
406 si
->volume
= (uint32_t) volume
;
410 static int pa_cli_command_sink_default(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
412 struct pa_sink
*sink
;
415 if (!(n
= pa_tokenizer_get(t
, 1))) {
416 pa_ioline_puts(c
->line
, "You need to specify a sink either by its name or its index.\n");
420 if (!(sink
= pa_namereg_get(c
->core
, n
, PA_NAMEREG_SINK
))) {
421 pa_ioline_puts(c
->line
, "No sink found by this name or index.\n");
425 c
->core
->default_sink_index
= sink
->index
;
429 static int pa_cli_command_source_default(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
431 struct pa_source
*source
;
434 if (!(n
= pa_tokenizer_get(t
, 1))) {
435 pa_ioline_puts(c
->line
, "You need to specify a source either by its name or its index.\n");
439 if (!(source
= pa_namereg_get(c
->core
, n
, PA_NAMEREG_SOURCE
))) {
440 pa_ioline_puts(c
->line
, "No source found by this name or index.\n");
444 c
->core
->default_source_index
= source
->index
;
448 static int pa_cli_command_kill_client(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
450 struct pa_client
*client
;
455 if (!(n
= pa_tokenizer_get(t
, 1))) {
456 pa_ioline_puts(c
->line
, "You need to specify a client by its index.\n");
460 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
461 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
465 if (!(client
= pa_idxset_get_by_index(c
->core
->clients
, index
))) {
466 pa_ioline_puts(c
->line
, "No client found by this index.\n");
470 ret
= (client
->userdata
== c
) ? -1 : 0;
471 pa_client_kill(client
);
475 static int pa_cli_command_kill_sink_input(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
477 struct pa_sink_input
*sink_input
;
481 if (!(n
= pa_tokenizer_get(t
, 1))) {
482 pa_ioline_puts(c
->line
, "You need to specify a sink input by its index.\n");
486 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
487 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
491 if (!(sink_input
= pa_idxset_get_by_index(c
->core
->sink_inputs
, index
))) {
492 pa_ioline_puts(c
->line
, "No sink input found by this index.\n");
496 pa_sink_input_kill(sink_input
);
500 static int pa_cli_command_kill_source_output(struct pa_cli
*c
, struct pa_tokenizer
*t
) {
502 struct pa_source_output
*source_output
;
506 if (!(n
= pa_tokenizer_get(t
, 1))) {
507 pa_ioline_puts(c
->line
, "You need to specify a source output by its index.\n");
511 if ((index
= parse_index(n
)) == PA_IDXSET_INVALID
) {
512 pa_ioline_puts(c
->line
, "Failed to parse index.\n");
516 if (!(source_output
= pa_idxset_get_by_index(c
->core
->source_outputs
, index
))) {
517 pa_ioline_puts(c
->line
, "No source output found by this index.\n");
521 pa_source_output_kill(source_output
);