From e61e9244aa082c07df4f21213cd3d223033fd03f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 14 Jul 2004 21:52:41 +0000 Subject: complete implementation of the command line git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@65 fefdeb5f-60dc-0310-8127-8f9354f1896f --- src/Makefile.am | 25 +-- src/cli-command.c | 531 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/cli-command.h | 11 ++ src/cli.c | 452 +++--------------------------------------- src/cmdline.c | 68 +++---- src/cmdline.h | 8 +- src/main.c | 45 +++-- src/module-oss-mmap.c | 2 +- src/module-oss.c | 2 +- src/polypaudio.run | 13 ++ src/strbuf.c | 14 +- src/strbuf.h | 1 + 12 files changed, 663 insertions(+), 509 deletions(-) create mode 100644 src/cli-command.c create mode 100644 src/cli-command.h create mode 100755 src/polypaudio.run diff --git a/src/Makefile.am b/src/Makefile.am index bdd621ab..c973af52 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,14 +28,11 @@ pkglib_LTLIBRARIES=libiochannel.la \ liboss-util.la \ libioline.la \ libcli.la \ - libtokenizer.la \ - libdynarray.la \ libprotocol-cli.la \ libtagstruct.la \ libpstream-util.la \ libpdispatch.la \ libauthkey.la \ - libclitext.la \ libsocket-util.la \ libprotocol-simple.la \ libprotocol-esound.la \ @@ -85,7 +82,11 @@ polypaudio_SOURCES = idxset.c idxset.h \ sconv-s16be.c sconv-s16be.h \ sioman.c sioman.h \ modargs.c modargs.h \ - cmdline.c cmdline.h + cmdline.c cmdline.h \ + cli-command.c cli-command.h \ + clitext.c clitext.h \ + tokenizer.c tokenizer.h \ + dynarray.c dynarray.h polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) polypaudio_INCLUDES = $(INCLTDL) @@ -118,7 +119,7 @@ libpdispatch_la_LIBADD = libtagstruct.la libiochannel_la_SOURCES = iochannel.c iochannel.h libiochannel_la_LDFLAGS = -avoid-version -libiochannel_la_LIBDADD = libsocket-util.la +libiochannel_la_LIBADD = libsocket-util.la libpacket_la_SOURCES = packet.c packet.h libpacket_la_LDFLAGS = -avoid-version @@ -132,14 +133,7 @@ libioline_la_LIBADD = libiochannel.la libcli_la_SOURCES = cli.c cli.h libcli_la_LDFLAGS = -avoid-version -libcli_la_LIBADD = libiochannel.la libioline.la libclitext.la libtokenizer.la - -libdynarray_la_SOURCES = dynarray.c dynarray.h -libdynarray_la_LDFLAGS = -avoid-version - -libtokenizer_la_SOURCES = tokenizer.c tokenizer.h -libtokenizer_la_LDFLAGS = -avoid-version -libtokenizer_la_LIBADD = libdynarray.la +libcli_la_LIBADD = libiochannel.la libioline.la libprotocol_cli_la_SOURCES = protocol-cli.c protocol-cli.h libprotocol_cli_la_LDFLAGS = -avoid-version @@ -159,9 +153,6 @@ libprotocol_esound_la_LIBADD = libsocket-server.la libiochannel.la libauthkey.la libauthkey_la_SOURCES = authkey.c authkey.h libauthkey_la_LDFLAGS = -avoid-version -libclitext_la_SOURCES = clitext.c clitext.h -libclitext_la_LDFLAGS = -avoid-version - libsocket_util_la_SOURCES = socket-util.c socket-util.h libsocket_util_la_LDFLAGS = -avoid-version @@ -219,7 +210,7 @@ module_oss_mmap_la_LIBADD = liboss-util.la module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version -module_cli_la_LIBADD = libcli.la libiochannel.la libtokenizer.la +module_cli_la_LIBADD = libcli.la libiochannel.la libpolyp_la_SOURCES = polyp.c polyp.h \ polypdef.h \ diff --git a/src/cli-command.c b/src/cli-command.c new file mode 100644 index 00000000..06e0eb30 --- /dev/null +++ b/src/cli-command.c @@ -0,0 +1,531 @@ +#include +#include +#include +#include +#include + +#include "cli-command.h" +#include "module.h" +#include "sink.h" +#include "source.h" +#include "client.h" +#include "sinkinput.h" +#include "sourceoutput.h" +#include "tokenizer.h" +#include "strbuf.h" +#include "namereg.h" +#include "clitext.h" + +struct command { + const char *name; + int (*proc) (struct pa_core *c, struct pa_tokenizer*t, struct pa_strbuf *buf, int *fail, int *verbose); + const char *help; + unsigned args; +}; + +static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); +static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose); + +static const struct command commands[] = { + { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, + { "help", pa_cli_command_help, "Show this help", 1 }, + { "modules", pa_cli_command_modules, "List loaded modules", 1 }, + { "sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, + { "sources", pa_cli_command_sources, "List loaded sources", 1 }, + { "clients", pa_cli_command_clients, "List loaded clients", 1 }, + { "sink_inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, + { "source_outputs", pa_cli_command_source_outputs, "List source outputs", 1 }, + { "stat", pa_cli_command_stat, "Show memory block statistics", 1 }, + { "info", pa_cli_command_info, "Show comprehensive status", 1 }, + { "ls", pa_cli_command_info, NULL, 1 }, + { "list", pa_cli_command_info, NULL, 1 }, + { "load", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, + { "unload", pa_cli_command_unload, "Unload a module (args: index)", 2}, + { "sink_volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, + { "sink_input_volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, + { "sink_default", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, + { "source_default", pa_cli_command_source_default, "Set the default source (args: index|name)", 2}, + { "kill_client", pa_cli_command_kill_client, "Kill a client (args: index)", 2}, + { "kill_sink_input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2}, + { "kill_source_output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2}, + { NULL, NULL, NULL, 0 } +}; + +static const char whitespace[] = " \t\n\r"; +static const char linebreak[] = "\n\r"; + +static uint32_t parse_index(const char *n) { + long index; + char *x; + index = strtol(n, &x, 0); + if (!x || *x != 0 || index < 0) + return (uint32_t) PA_IDXSET_INVALID; + + return (uint32_t) index; +} + +static int pa_cli_command_exit(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + assert(c && c->mainloop && t); + c->mainloop->quit(c->mainloop, 0); + return 0; +} + +static int pa_cli_command_help(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const struct command*command; + assert(c && t && buf); + + pa_strbuf_puts(buf, "Available commands:\n"); + + for (command = commands; command->name; command++) + if (command->help) + pa_strbuf_printf(buf, " %-20s %s\n", command->name, command->help); + return 0; +} + +static int pa_cli_command_modules(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_module_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_clients(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_client_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_sinks(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_sink_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_sources(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_source_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_sink_inputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_sink_input_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_source_outputs(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + char *s; + assert(c && t); + s = pa_source_output_list_to_string(c); + assert(s); + pa_strbuf_puts(buf, s); + free(s); + return 0; +} + +static int pa_cli_command_stat(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + assert(c && t); + pa_strbuf_printf(buf, "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count, pa_memblock_total); + return 0; +} + +static int pa_cli_command_info(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + assert(c && t); + pa_cli_command_stat(c, t, buf, fail, verbose); + pa_cli_command_modules(c, t, buf, fail, verbose); + pa_cli_command_sinks(c, t, buf, fail, verbose); + pa_cli_command_sources(c, t, buf, fail, verbose); + pa_cli_command_clients(c, t, buf, fail, verbose); + pa_cli_command_sink_inputs(c, t, buf, fail, verbose); + pa_cli_command_source_outputs(c, t, buf, fail, verbose); + return 0; +} + +static int pa_cli_command_load(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + struct pa_module *m; + const char *name; + char txt[256]; + assert(c && t); + + if (!(name = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify the module name and optionally arguments.\n"); + return -1; + } + + if (!(m = pa_module_load(c, name, pa_tokenizer_get(t, 2)))) { + pa_strbuf_puts(buf, "Module load failed.\n"); + return -1; + } + + if (*verbose) + snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index); + pa_strbuf_puts(buf, txt); + return 0; +} + +static int pa_cli_command_unload(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + struct pa_module *m; + uint32_t index; + const char *i; + char *e; + assert(c && t); + + if (!(i = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify the module index.\n"); + return -1; + } + + index = (uint32_t) strtoul(i, &e, 10); + if (*e || !(m = pa_idxset_get_by_index(c->modules, index))) { + pa_strbuf_puts(buf, "Invalid module index.\n"); + return -1; + } + + pa_module_unload_request(c, m); + return 0; +} + +static int pa_cli_command_sink_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n, *v; + char *x = NULL; + struct pa_sink *sink; + long volume; + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); + return -1; + } + + if (!(v = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + return -1; + } + + volume = strtol(v, &x, 0); + if (!x || *x != 0 || volume < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + sink->volume = (uint32_t) volume; + return 0; +} + +static int pa_cli_command_sink_input_volume(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n, *v; + struct pa_sink_input *si; + long volume; + uint32_t index; + char *x; + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); + return -1; + } + + if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(v = pa_tokenizer_get(t, 2))) { + pa_strbuf_puts(buf, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); + return -1; + } + + x = NULL; + volume = strtol(v, &x, 0); + if (!x || *x != 0 || volume < 0) { + pa_strbuf_puts(buf, "Failed to parse volume.\n"); + return -1; + } + + if (!(si = pa_idxset_get_by_index(c->sink_inputs, (uint32_t) index))) { + pa_strbuf_puts(buf, "No sink input found with this index.\n"); + return -1; + } + + si->volume = (uint32_t) volume; + return 0; +} + +static int pa_cli_command_sink_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + struct pa_sink *sink; + assert(c && t); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); + return -1; + } + + if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) { + pa_strbuf_puts(buf, "No sink found by this name or index.\n"); + return -1; + } + + c->default_sink_index = sink->index; + return 0; +} + +static int pa_cli_command_source_default(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + struct pa_source *source; + assert(c && t); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n"); + return -1; + } + + if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) { + pa_strbuf_puts(buf, "No source found by this name or index.\n"); + return -1; + } + + c->default_source_index = source->index; + return 0; +} + +static int pa_cli_command_kill_client(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + struct pa_client *client; + uint32_t index; + assert(c && t); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a client by its index.\n"); + return -1; + } + + if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(client = pa_idxset_get_by_index(c->clients, index))) { + pa_strbuf_puts(buf, "No client found by this index.\n"); + return -1; + } + + pa_client_kill(client); + return 0; +} + +static int pa_cli_command_kill_sink_input(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + struct pa_sink_input *sink_input; + uint32_t index; + assert(c && t); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a sink input by its index.\n"); + return -1; + } + + if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(sink_input = pa_idxset_get_by_index(c->sink_inputs, index))) { + pa_strbuf_puts(buf, "No sink input found by this index.\n"); + return -1; + } + + pa_sink_input_kill(sink_input); + return 0; +} + +static int pa_cli_command_kill_source_output(struct pa_core *c, struct pa_tokenizer *t, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *n; + struct pa_source_output *source_output; + uint32_t index; + assert(c && t); + + if (!(n = pa_tokenizer_get(t, 1))) { + pa_strbuf_puts(buf, "You need to specify a source output by its index.\n"); + return -1; + } + + if ((index = parse_index(n)) == PA_IDXSET_INVALID) { + pa_strbuf_puts(buf, "Failed to parse index.\n"); + return -1; + } + + if (!(source_output = pa_idxset_get_by_index(c->source_outputs, index))) { + pa_strbuf_puts(buf, "No source output found by this index.\n"); + return -1; + } + + pa_source_output_kill(source_output); + return 0; +} + +int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *cs; + + cs = s+strspn(s, whitespace); + + if (*cs == '#' || !*cs) + return 0; + else if (*cs == '.') { + static const char fail_meta[] = ".fail"; + static const char nofail_meta[] = ".nofail"; + static const char verbose_meta[] = ".verbose"; + static const char noverbose_meta[] = ".noverbose"; + + if (!strcmp(cs, verbose_meta)) + *verbose = 1; + else if (!strcmp(cs, noverbose_meta)) + *verbose = 0; + else if (!strcmp(cs, fail_meta)) + *fail = 1; + else if (!strcmp(cs, nofail_meta)) + *fail = 0; + else { + size_t l; + static const char include_meta[] = ".include"; + l = strcspn(cs, whitespace); + + if (l == sizeof(include_meta)-1 && !strncmp(cs, include_meta, l)) { + const char *filename = cs+l+strspn(cs+l, whitespace); + + if (pa_cli_command_execute_file(c, filename, buf, fail, verbose) < 0) + if (*fail) return -1; + } else { + pa_strbuf_printf(buf, "Invalid meta command: %s\n", cs); + if (*fail) return -1; + } + } + } else { + const struct command*command; + int unknown = 1; + size_t l; + + l = strcspn(cs, whitespace); + + for (command = commands; command->name; command++) + if (strlen(command->name) == l && !strncmp(cs, command->name, l)) { + int ret; + struct pa_tokenizer *t = pa_tokenizer_new(cs, command->args); + assert(t); + ret = command->proc(c, t, buf, fail, verbose); + pa_tokenizer_free(t); + unknown = 0; + + if (ret < 0 && *fail) + return -1; + + break; + } + + if (unknown) { + pa_strbuf_printf(buf, "Unknown command: %s\n", cs); + if (*fail) + return -1; + } + } + + return 0; +} + +int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail, int *verbose) { + char line[256]; + FILE *f = NULL; + int ret = -1; + assert(c && fn && buf); + + if (!(f = fopen(fn, "r"))) { + pa_strbuf_printf(buf, "open('%s') failed: %s\n", fn, strerror(errno)); + if (!*fail) + ret = 0; + goto fail; + } + + if (*verbose) + pa_strbuf_printf(buf, "Executing file: '%s'\n", fn); + + while (fgets(line, sizeof(line), f)) { + char *e = line + strcspn(line, linebreak); + *e = 0; + + if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0 && *fail) + goto fail; + } + + if (*verbose) + pa_strbuf_printf(buf, "Executed file: '%s'\n", fn); + + ret = 0; + +fail: + if (f) + fclose(f); + + return ret; +} + +int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose) { + const char *p; + assert(c && s && buf && fail && verbose); + + p = s; + while (*p) { + size_t l = strcspn(p, linebreak); + char *line = strndup(p, l); + assert(line); + + if (pa_cli_command_execute_line(c, line, buf, fail, verbose) < 0&& *fail) { + free(line); + return -1; + } + free(line); + + p += l; + p += strspn(p, linebreak); + } + + return 0; +} diff --git a/src/cli-command.h b/src/cli-command.h new file mode 100644 index 00000000..f95261b7 --- /dev/null +++ b/src/cli-command.h @@ -0,0 +1,11 @@ +#ifndef fooclicommandhfoo +#define fooclicommandhfoo + +#include "strbuf.h" +#include "core.h" + +int pa_cli_command_execute_line(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose); +int pa_cli_command_execute_file(struct pa_core *c, const char *fn, struct pa_strbuf *buf, int *fail, int *verbose); +int pa_cli_command_execute(struct pa_core *c, const char *s, struct pa_strbuf *buf, int *fail, int *verbose); + +#endif diff --git a/src/cli.c b/src/cli.c index d5b46c46..b4d6625d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -15,6 +15,7 @@ #include "strbuf.h" #include "namereg.h" #include "clitext.h" +#include "cli-command.h" struct pa_cli { struct pa_core *core; @@ -24,62 +25,12 @@ struct pa_cli { void *userdata; struct pa_client *client; -}; -struct command { - const char *name; - int (*proc) (struct pa_cli *cli, struct pa_tokenizer*t); - const char *help; - unsigned args; + int fail, verbose, kill_requested, defer_kill; }; static void line_callback(struct pa_ioline *line, const char *s, void *userdata); -static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t); -static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t); - -static const struct command commands[] = { - { "exit", pa_cli_command_exit, "Terminate the daemon", 1 }, - { "help", pa_cli_command_help, "Show this help", 1 }, - { "modules", pa_cli_command_modules, "List loaded modules", 1 }, - { "sinks", pa_cli_command_sinks, "List loaded sinks", 1 }, - { "sources", pa_cli_command_sources, "List loaded sources", 1 }, - { "clients", pa_cli_command_clients, "List loaded clients", 1 }, - { "sink_inputs", pa_cli_command_sink_inputs, "List sink inputs", 1 }, - { "source_outputs", pa_cli_command_source_outputs, "List source outputs", 1 }, - { "stat", pa_cli_command_stat, "Show memory block statistics", 1 }, - { "info", pa_cli_command_info, "Show comprehensive status", 1 }, - { "ls", pa_cli_command_info, NULL, 1 }, - { "list", pa_cli_command_info, NULL, 1 }, - { "load", pa_cli_command_load, "Load a module (args: name, arguments)", 3}, - { "unload", pa_cli_command_unload, "Unload a module (args: index)", 2}, - { "sink_volume", pa_cli_command_sink_volume, "Set the volume of a sink (args: index|name, volume)", 3}, - { "sink_input_volume", pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: index|name, volume)", 3}, - { "sink_default", pa_cli_command_sink_default, "Set the default sink (args: index|name)", 2}, - { "source_default", pa_cli_command_source_default, "Set the default source (args: index|name)", 2}, - { "kill_client", pa_cli_command_kill_client, "Kill a client (args: index)", 2}, - { "kill_sink_input", pa_cli_command_kill_sink_input, "Kill a sink input (args: index)", 2}, - { "kill_source_output", pa_cli_command_kill_source_output, "Kill a source output (args: index)", 2}, - { NULL, NULL, NULL, 0 } -}; - static const char prompt[] = ">>> "; static void client_kill(struct pa_client *c); @@ -108,6 +59,9 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io, struct pa_ioline_set_callback(c->line, line_callback, c); pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n"); pa_ioline_puts(c->line, prompt); + + c->fail = c->kill_requested = c->defer_kill = 0; + c->verbose = 1; return c; } @@ -123,16 +77,20 @@ static void client_kill(struct pa_client *client) { struct pa_cli *c; assert(client && client->userdata); c = client->userdata; + fprintf(stderr, "CLI client killed.\n"); - - if (c->eof_callback) - c->eof_callback(c, c->userdata); + if (c->defer_kill) + c->kill_requested = 1; + else { + if (c->eof_callback) + c->eof_callback(c, c->userdata); + } } static void line_callback(struct pa_ioline *line, const char *s, void *userdata) { + struct pa_strbuf *buf; struct pa_cli *c = userdata; - const char *cs; - const char delimiter[] = " \t\n\r"; + char *p; assert(line && c); if (!s) { @@ -143,34 +101,19 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata) return; } - cs = s+strspn(s, delimiter); - if (*cs && *cs != '#') { - const struct command*command; - int unknown = 1; - size_t l; - - l = strcspn(s, delimiter); - - for (command = commands; command->name; command++) - if (strlen(command->name) == l && !strncmp(s, command->name, l)) { - int ret; - struct pa_tokenizer *t = pa_tokenizer_new(s, command->args); - assert(t); - ret = command->proc(c, t); - pa_tokenizer_free(t); - unknown = 0; - - /* A negative return value denotes that the cli object is probably invalid now */ - if (ret < 0) - return; - break; - } + buf = pa_strbuf_new(); + assert(buf); + c->defer_kill++; + pa_cli_command_execute_line(c->core, s, buf, &c->fail, &c->verbose); + c->defer_kill--; + pa_ioline_puts(line, p = pa_strbuf_tostring_free(buf)); + free(p); - if (unknown) - pa_ioline_puts(line, "Unknown command\n"); - } - - pa_ioline_puts(line, prompt); + if (c->kill_requested) { + if (c->eof_callback) + c->eof_callback(c, c->userdata); + } else + pa_ioline_puts(line, prompt); } void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void *userdata), void *userdata) { @@ -178,346 +121,3 @@ void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void c->eof_callback = cb; c->userdata = userdata; } - -static uint32_t parse_index(const char *n) { - long index; - char *x; - index = strtol(n, &x, 0); - if (!x || *x != 0 || index < 0) - return (uint32_t) PA_IDXSET_INVALID; - - return (uint32_t) index; -} - -static int pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t) { - assert(c && c->core && c->core->mainloop && t); - c->core->mainloop->quit(c->core->mainloop, 0); - return 0; -} - -static int pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) { - const struct command*command; - struct pa_strbuf *pa_strbuf; - char *p; - assert(c && t); - - pa_strbuf = pa_strbuf_new(); - assert(pa_strbuf); - - pa_strbuf_puts(pa_strbuf, "Available commands:\n"); - - for (command = commands; command->name; command++) - if (command->help) - pa_strbuf_printf(pa_strbuf, " %-20s %s\n", command->name, command->help); - - pa_ioline_puts(c->line, p = pa_strbuf_tostring_free(pa_strbuf)); - free(p); - return 0; -} - -static int pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_module_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_client_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_sink_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_source_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_sink_input_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) { - char *s; - assert(c && t); - s = pa_source_output_list_to_string(c->core); - assert(s); - pa_ioline_puts(c->line, s); - free(s); - return 0; -} - -static int pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t) { - char txt[256]; - assert(c && t); - snprintf(txt, sizeof(txt), "Memory blocks allocated: %u, total size: %u bytes.\n", pa_memblock_count, pa_memblock_total); - pa_ioline_puts(c->line, txt); - return 0; -} - -static int pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t) { - assert(c && t); - pa_cli_command_stat(c, t); - pa_cli_command_modules(c, t); - pa_cli_command_sinks(c, t); - pa_cli_command_sources(c, t); - pa_cli_command_clients(c, t); - pa_cli_command_sink_inputs(c, t); - pa_cli_command_source_outputs(c, t); - return 0; -} - -static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) { - struct pa_module *m; - const char *name; - char txt[256]; - assert(c && t); - - if (!(name = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specfiy the module name and optionally arguments.\n"); - return 0; - } - - if (!(m = pa_module_load(c->core, name, pa_tokenizer_get(t, 2)))) { - pa_ioline_puts(c->line, "Module load failed.\n"); - return 0; - } - - snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index); - pa_ioline_puts(c->line, txt); - return 0; -} - -static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) { - struct pa_module *m; - uint32_t index; - const char *i; - char *e; - assert(c && t); - - if (!(i = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specfiy the module index.\n"); - return 0; - } - - index = (uint32_t) strtoul(i, &e, 10); - if (*e || !(m = pa_idxset_get_by_index(c->core->modules, index))) { - pa_ioline_puts(c->line, "Invalid module index.\n"); - return 0; - } - - pa_module_unload_request(c->core, m); - return 0; -} - -static int pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n, *v; - char *x = NULL; - struct pa_sink *sink; - long volume; - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n"); - return 0; - } - - if (!(v = pa_tokenizer_get(t, 2))) { - pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); - return 0; - } - - volume = strtol(v, &x, 0); - if (!x || *x != 0 || volume < 0) { - pa_ioline_puts(c->line, "Failed to parse volume.\n"); - return 0; - } - - if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) { - pa_ioline_puts(c->line, "No sink found by this name or index.\n"); - return 0; - } - - sink->volume = (uint32_t) volume; - return 0; -} - -static int pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n, *v; - struct pa_sink_input *si; - long volume; - uint32_t index; - char *x; - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n"); - return 0; - } - - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { - pa_ioline_puts(c->line, "Failed to parse index.\n"); - return 0; - } - - if (!(v = pa_tokenizer_get(t, 2))) { - pa_ioline_puts(c->line, "You need to specify a volume >= 0. (0 is muted, 0x100 is normal volume)\n"); - return 0; - } - - x = NULL; - volume = strtol(v, &x, 0); - if (!x || *x != 0 || volume < 0) { - pa_ioline_puts(c->line, "Failed to parse volume.\n"); - return 0; - } - - if (!(si = pa_idxset_get_by_index(c->core->sink_inputs, (uint32_t) index))) { - pa_ioline_puts(c->line, "No sink input found with this index.\n"); - return 0; - } - - si->volume = (uint32_t) volume; - return 0; -} - -static int pa_cli_command_sink_default(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n; - struct pa_sink *sink; - assert(c && t); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a sink either by its name or its index.\n"); - return 0; - } - - if (!(sink = pa_namereg_get(c->core, n, PA_NAMEREG_SINK))) { - pa_ioline_puts(c->line, "No sink found by this name or index.\n"); - return 0; - } - - c->core->default_sink_index = sink->index; - return 0; -} - -static int pa_cli_command_source_default(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n; - struct pa_source *source; - assert(c && t); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a source either by its name or its index.\n"); - return 0; - } - - if (!(source = pa_namereg_get(c->core, n, PA_NAMEREG_SOURCE))) { - pa_ioline_puts(c->line, "No source found by this name or index.\n"); - return 0; - } - - c->core->default_source_index = source->index; - return 0; -} - -static int pa_cli_command_kill_client(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n; - struct pa_client *client; - uint32_t index; - int ret; - assert(c && t); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a client by its index.\n"); - return 0; - } - - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { - pa_ioline_puts(c->line, "Failed to parse index.\n"); - return 0; - } - - if (!(client = pa_idxset_get_by_index(c->core->clients, index))) { - pa_ioline_puts(c->line, "No client found by this index.\n"); - return 0; - } - - ret = (client->userdata == c) ? -1 : 0; - pa_client_kill(client); - return ret; -} - -static int pa_cli_command_kill_sink_input(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n; - struct pa_sink_input *sink_input; - uint32_t index; - assert(c && t); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a sink input by its index.\n"); - return 0; - } - - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { - pa_ioline_puts(c->line, "Failed to parse index.\n"); - return 0; - } - - if (!(sink_input = pa_idxset_get_by_index(c->core->sink_inputs, index))) { - pa_ioline_puts(c->line, "No sink input found by this index.\n"); - return 0; - } - - pa_sink_input_kill(sink_input); - return 0; -} - -static int pa_cli_command_kill_source_output(struct pa_cli *c, struct pa_tokenizer *t) { - const char *n; - struct pa_source_output *source_output; - uint32_t index; - assert(c && t); - - if (!(n = pa_tokenizer_get(t, 1))) { - pa_ioline_puts(c->line, "You need to specify a source output by its index.\n"); - return 0; - } - - if ((index = parse_index(n)) == PA_IDXSET_INVALID) { - pa_ioline_puts(c->line, "Failed to parse index.\n"); - return 0; - } - - if (!(source_output = pa_idxset_get_by_index(c->core->source_outputs, index))) { - pa_ioline_puts(c->line, "No source output found by this index.\n"); - return 0; - } - - pa_source_output_kill(source_output); - return 0; -} diff --git a/src/cmdline.c b/src/cmdline.c index 36fe3e61..d53d028b 100644 --- a/src/cmdline.c +++ b/src/cmdline.c @@ -6,6 +6,7 @@ #include "cmdline.h" #include "util.h" +#include "strbuf.h" void pa_cmdline_help(const char *argv0) { const char *e; @@ -17,56 +18,38 @@ void pa_cmdline_help(const char *argv0) { printf("%s [options]\n" " -L MODULE Load the specified plugin module with the specified argument\n" - " -F FILE A shortcut for '-L module-cli file=FILE', i.e. run the specified script after startup\n" - " -C A shortcut for '-L module-cli', i.e. open a command line on the running TTY\n" + " -F FILE Run the specified script\n" + " -C Open a command line on the running TTY\n" " -D Daemonize after loading the modules\n" + " -f Dont quit when the startup fails\n" + " -v Verbose startup\n" " -h Show this help\n", e); } -static void add_module(struct pa_cmdline *cmdline, char *name, char *arguments) { - struct pa_cmdline_module *m; - assert(cmdline && name); - - m = malloc(sizeof(struct pa_cmdline_module)); - assert(m); - m->name = name; - m->arguments = name; - m->next = NULL; - - if (cmdline->last_module) - cmdline->last_module->next = m; - else { - assert(!cmdline->first_module); - cmdline->first_module = m; - } - cmdline->last_module = m; -} - struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { char c; struct pa_cmdline *cmdline = NULL; + struct pa_strbuf *buf = NULL; assert(argc && argv); cmdline = malloc(sizeof(struct pa_cmdline)); assert(cmdline); - cmdline->daemonize = cmdline->help = 0; - cmdline->first_module = cmdline->last_module = NULL; + cmdline->daemonize = cmdline->help = cmdline->verbose = 0; + cmdline->fail = 1; + + buf = pa_strbuf_new(); + assert(buf); - while ((c = getopt(argc, argv, "L:F:CDh")) != -1) { + while ((c = getopt(argc, argv, "L:F:CDhfv")) != -1) { switch (c) { - case 'L': { - char *space; - if ((space = strchr(optarg, ' '))) - add_module(cmdline, strndup(optarg, space-optarg), space+1); - else - add_module(cmdline, strdup(optarg), NULL); + case 'L': + pa_strbuf_printf(buf, "load %s\n", optarg); break; - } case 'F': - add_module(cmdline, strdup("module-cli"), pa_sprintf_malloc("file='%s'", optarg)); + pa_strbuf_printf(buf, ".include %s\n", optarg); break; case 'C': - add_module(cmdline, strdup("module-cli"), NULL); + pa_strbuf_puts(buf, "load module-cli\n"); break; case 'D': cmdline->daemonize = 1; @@ -74,29 +57,30 @@ struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []) { case 'h': cmdline->help = 1; break; + case 'f': + cmdline->fail = 0; + break; + case 'v': + cmdline->verbose = 0; + break; default: goto fail; } } + cmdline->cli_commands = pa_strbuf_tostring_free(buf); return cmdline; fail: if (cmdline) pa_cmdline_free(cmdline); + if (buf) + pa_strbuf_free(buf); return NULL; } void pa_cmdline_free(struct pa_cmdline *cmd) { - struct pa_cmdline_module *m; assert(cmd); - - while ((m = cmd->first_module)) { - cmd->first_module = m->next; - free(m->name); - free(m->arguments); - free(m); - } - + free(cmd->cli_commands); free(cmd); } diff --git a/src/cmdline.h b/src/cmdline.h index 9a647706..ec2dd0c2 100644 --- a/src/cmdline.h +++ b/src/cmdline.h @@ -1,14 +1,10 @@ #ifndef foocmdlinehfoo #define foocmdlinehfoo -struct pa_cmdline_module { - char *name, *arguments; - struct pa_cmdline_module *next; -}; struct pa_cmdline { - int daemonize, help; - struct pa_cmdline_module *first_module, *last_module; + int daemonize, help, fail, verbose; + char *cli_commands; }; struct pa_cmdline* pa_cmdline_parse(int argc, char * const argv []); diff --git a/src/main.c b/src/main.c index e2c8eb63..d2ae61c9 100644 --- a/src/main.c +++ b/src/main.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,6 +11,7 @@ #include "module.h" #include "mainloop-signal.h" #include "cmdline.h" +#include "cli-command.h" static struct pa_mainloop *mainloop; @@ -28,10 +30,12 @@ static void aux_signal_callback(void *id, int sig, void *userdata) { int main(int argc, char *argv[]) { struct pa_core *c; struct pa_cmdline *cmdline = NULL; + struct pa_strbuf *buf = NULL; + char *s; int r, retval = 0; if (!(cmdline = pa_cmdline_parse(argc, argv))) { - fprintf(stderr, "Failed to parse command line.\n"); + fprintf(stderr, __FILE__": failed to parse command line.\n"); return 1; } @@ -55,33 +59,48 @@ int main(int argc, char *argv[]) { c = pa_core_new(pa_mainloop_get_api(mainloop)); assert(c); - pa_module_load(c, "module-oss-mmap", "device=/dev/dsp playback=1 record=1"); -/* pa_module_load(c, "module-oss-mmap", "/dev/dsp1");*/ -/* pa_module_load(c, "module-pipe-sink", NULL);*/ +/* pa_module_load(c, "module-oss-mmap", "device=/dev/dsp playback=1 record=1"); + pa_module_load(c, "module-oss-mmap", "/dev/dsp1"); + pa_module_load(c, "module-pipe-sink", NULL); pa_module_load(c, "module-simple-protocol-tcp", NULL); -/* pa_module_load(c, "module-simple-protocol-unix", NULL); + pa_module_load(c, "module-simple-protocol-unix", NULL); pa_module_load(c, "module-cli-protocol-tcp", NULL); pa_module_load(c, "module-cli-protocol-unix", NULL); - pa_module_load(c, "module-native-protocol-tcp", NULL);*/ + pa_module_load(c, "module-native-protocol-tcp", NULL); pa_module_load(c, "module-native-protocol-unix", NULL); pa_module_load(c, "module-esound-protocol-tcp", NULL); - pa_module_load(c, "module-cli", NULL); + pa_module_load(c, "module-cli", NULL);*/ pa_signal_register(SIGUSR1, aux_signal_callback, c); pa_signal_register(SIGUSR2, aux_signal_callback, c); + + buf = pa_strbuf_new(); + assert(buf); + r = pa_cli_command_execute(c, cmdline->cli_commands, buf, &cmdline->fail, &cmdline->verbose); + fprintf(stderr, s = pa_strbuf_tostring_free(buf)); + free(s); - fprintf(stderr, "main: mainloop entry.\n"); - if (pa_mainloop_run(mainloop, &retval) < 0) + if (r < 0 && cmdline->fail) { + fprintf(stderr, __FILE__": failed to initialize daemon.\n"); retval = 1; - fprintf(stderr, "main: mainloop exit.\n"); - + } else if (!c->modules || pa_idxset_ncontents(c->modules) == 0) { + fprintf(stderr, __FILE__": daemon startup without any loaded modules, refusing to work.\n"); + retval = 1; + } else { + fprintf(stderr, __FILE__": mainloop entry.\n"); + if (pa_mainloop_run(mainloop, &retval) < 0) + retval = 1; + fprintf(stderr, __FILE__": mainloop exit.\n"); + } + + pa_core_free(c); pa_signal_done(); pa_mainloop_free(mainloop); + + pa_cmdline_free(cmdline); - - lt_dlexit(); return retval; diff --git a/src/module-oss-mmap.c b/src/module-oss-mmap.c index a9e13086..020daa2c 100644 --- a/src/module-oss-mmap.c +++ b/src/module-oss-mmap.c @@ -270,7 +270,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { fprintf(stderr, "module-oss-mmap: mmap filed for output. Changing to O_RDONLY mode.\n"); mode = O_RDONLY; } else { - fprintf(stderr, "modeule-oss-mmap: mmap(): %s\n", strerror(errno)); + fprintf(stderr, "module-oss-mmap: mmap(): %s\n", strerror(errno)); goto fail; } } else { diff --git a/src/module-oss.c b/src/module-oss.c index 31ca2dba..5a6513c3 100644 --- a/src/module-oss.c +++ b/src/module-oss.c @@ -195,7 +195,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); - u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); + u->source->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); } else u->source = NULL; diff --git a/src/polypaudio.run b/src/polypaudio.run new file mode 100755 index 00000000..f82ad40e --- /dev/null +++ b/src/polypaudio.run @@ -0,0 +1,13 @@ +#!./polypaudio -F + +# Load the CLI module +load module-cli + +load module-esound-protocol-tcp +load module-simple-protocol-tcp +load module-native-protocol-unix +load module-cli-protocol-unix + +load module-oss-mmap device="/dev/dsp" + +load module-cli diff --git a/src/strbuf.c b/src/strbuf.c index 2082002a..41c139bd 100644 --- a/src/strbuf.c +++ b/src/strbuf.c @@ -5,6 +5,8 @@ #include #include +#include "strbuf.h" + struct chunk { struct chunk *next; size_t length; @@ -63,11 +65,17 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb) { } void pa_strbuf_puts(struct pa_strbuf *sb, const char *t) { - struct chunk *c; - size_t l; assert(sb && t); + pa_strbuf_putsn(sb, t, strlen(t)); +} - l = strlen(t); +void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t l) { + struct chunk *c; + assert(sb && t); + + if (!l) + return; + c = malloc(sizeof(struct chunk)+l); assert(c); diff --git a/src/strbuf.h b/src/strbuf.h index ab0c6a74..0e9bb5e3 100644 --- a/src/strbuf.h +++ b/src/strbuf.h @@ -10,5 +10,6 @@ char *pa_strbuf_tostring_free(struct pa_strbuf *sb); int pa_strbuf_printf(struct pa_strbuf *sb, const char *format, ...) __attribute__ ((format (printf, 2, 3)));; void pa_strbuf_puts(struct pa_strbuf *sb, const char *t); +void pa_strbuf_putsn(struct pa_strbuf *sb, const char *t, size_t m); #endif -- cgit