add kill_* and default_* commands to CLI
authorLennart Poettering <lennart@poettering.net>
Sun, 4 Jul 2004 17:40:15 +0000 (17:40 +0000)
committerLennart Poettering <lennart@poettering.net>
Sun, 4 Jul 2004 17:40:15 +0000 (17:40 +0000)
make module-cli unload itself on EOF
clean up stdio usage
add sink pointer to monitor sources

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@50 fefdeb5f-60dc-0310-8127-8f9354f1896f

13 files changed:
src/Makefile.am
src/cli.c
src/client.c
src/ioline.c
src/main.c
src/main.h [deleted file]
src/module-cli.c
src/sink.c
src/sioman.c [new file with mode: 0644]
src/sioman.h [new file with mode: 0644]
src/source.c
src/source.h
src/todo

index 167bc91..62b1a3a 100644 (file)
@@ -54,7 +54,7 @@ pkglib_LTLIBRARIES=libiochannel.la \
 polypaudio_SOURCES = idxset.c idxset.h \
                queue.c queue.h \
                strbuf.c strbuf.h \
-               main.c main.h \
+               main.c \
                mainloop.c mainloop.h \
                memblock.c memblock.h \
                sample.c sample.h \
@@ -77,7 +77,9 @@ polypaudio_SOURCES = idxset.c idxset.h \
                endianmacros.h \
                memchunk.c memchunk.h \
                sconv-s16le.c sconv-s16le.h \
-               sconv-s16be.c sconv-s16be.h
+               sconv-s16be.c sconv-s16be.h \
+               sioman.c sioman.h
+
 polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS)
 polypaudio_INCLUDES = $(INCLTDL)
 polypaudio_LDADD = $(LIBLTDL) $(LIBSAMPLERATE_LIBS)
index 659523b..ecde576 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -27,48 +27,62 @@ struct pa_cli {
 
 struct command {
     const char *name;
-    void (*proc) (struct pa_cli *cli, struct pa_tokenizer*t);
+    int (*proc) (struct pa_cli *cli, struct pa_tokenizer*t);
     const char *help;
     unsigned args;
 };
 
 static void line_callback(struct pa_ioline *line, const char *s, void *userdata);
 
-static void pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t);
-static void pa_cli_command_sink_input_volume(struct pa_cli *c, struct pa_tokenizer *t);
+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 },
-    { "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: sink, volume)",             3},
-    { "sink_input_volume",       pa_cli_command_sink_input_volume, "Set the volume of a sink input (args: sink input, volume)", 3},
+    { "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);
+
 struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io) {
     char cname[256];
     struct pa_cli *c;
@@ -86,6 +100,8 @@ struct pa_cli* pa_cli_new(struct pa_core *core, struct pa_iochannel *io) {
     pa_iochannel_peer_to_string(io, cname, sizeof(cname));
     c->client = pa_client_new(core, "CLI", cname);
     assert(c->client);
+    c->client->kill = client_kill;
+    c->client->userdata = c;
     
     pa_ioline_set_callback(c->line, line_callback, c);
     pa_ioline_puts(c->line, "Welcome to polypaudio! Use \"help\" for usage information.\n");
@@ -101,6 +117,16 @@ void pa_cli_free(struct pa_cli *c) {
     free(c);
 }
 
+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);
+}
+
 static void line_callback(struct pa_ioline *line, const char *s, void *userdata) {
     struct pa_cli *c = userdata;
     const char *cs;
@@ -108,7 +134,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata)
     assert(line && c);
 
     if (!s) {
-        fprintf(stderr, "CLI client exited\n");
+        fprintf(stderr, "CLI got EOF from user.\n");
         if (c->eof_callback)
             c->eof_callback(c, c->userdata);
 
@@ -125,11 +151,16 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata)
 
         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);
-                command->proc(c, 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;
             }
 
@@ -137,7 +168,7 @@ static void line_callback(struct pa_ioline *line, const char *s, void *userdata)
             pa_ioline_puts(line, "Unknown command\n");
     }
     
-    pa_ioline_puts(c->line, prompt);
+    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) {
@@ -146,12 +177,23 @@ void pa_cli_set_eof_callback(struct pa_cli *c, void (*cb)(struct pa_cli*c, void
     c->userdata = userdata;
 }
 
-static void pa_cli_command_exit(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) {
+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;
@@ -163,85 +205,95 @@ static void pa_cli_command_help(struct pa_cli *c, struct pa_tokenizer *t) {
     pa_strbuf_puts(pa_strbuf, "Available commands:\n");
     
     for (command = commands; command->name; command++)
-        pa_strbuf_printf(pa_strbuf, "    %-20s %s\n", command->name, command->help);
+        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 void pa_cli_command_modules(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_clients(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_sinks(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_sources(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_sink_inputs(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_source_outputs(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_stat(struct pa_cli *c, struct pa_tokenizer *t) {
+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 void pa_cli_command_info(struct pa_cli *c, struct pa_tokenizer *t) {
+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_sources(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 void pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) {
+static int pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *t) {
     struct pa_module *m;
     const char *name;
     char txt[256];
@@ -249,19 +301,20 @@ static void pa_cli_command_load(struct pa_cli *c, struct pa_tokenizer *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;
+        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;
+        return 0;
     }
 
     snprintf(txt, sizeof(txt), "Module successfully loaded, index: %u.\n", m->index);
     pa_ioline_puts(c->line, txt);
+    return 0;
 }
 
-static void pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
+static int pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
     struct pa_module *m;
     uint32_t index;
     const char *i;
@@ -270,20 +323,20 @@ static void pa_cli_command_unload(struct pa_cli *c, struct pa_tokenizer *t) {
 
     if (!(i = pa_tokenizer_get(t, 1))) {
         pa_ioline_puts(c->line, "You need to specfiy the module index.\n");
-        return;
+        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;
+        return 0;
     }
 
     pa_module_unload_request(c->core, m);
+    return 0;
 }
 
-
-static void pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *t) {
+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;
@@ -291,62 +344,178 @@ static void pa_cli_command_sink_volume(struct pa_cli *c, struct pa_tokenizer *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;
+        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;
+        return 0;
     }
 
     volume = strtol(v, &x, 0);
     if (!x || *x != 0 || volume < 0) {
         pa_ioline_puts(c->line, "Failed to parse volume.\n");
-        return;
+        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;
+        return 0;
     }
 
     sink->volume = (uint32_t) volume;
+    return 0;
 }
 
-static void pa_cli_command_sink_input_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) {
     const char *n, *v;
-    char *x = NULL;
     struct pa_sink_input *si;
-    long index, volume;
+    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;
+        return 0;
     }
 
-    index = strtol(n, &x, 0);
-    if (!x || *x != 0 || index < 0) {
+    if ((index = parse_index(n)) == PA_IDXSET_INVALID) {
         pa_ioline_puts(c->line, "Failed to parse index.\n");
-        return;
+        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;
+        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;
+        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;
+        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;
+}
index eb06c52..7f1648a 100644 (file)
@@ -39,8 +39,12 @@ void pa_client_free(struct pa_client *c) {
 
 void pa_client_kill(struct pa_client *c) {
     assert(c);
-    if (c->kill)
-        c->kill(c);
+    if (!c->kill) {
+        fprintf(stderr, "kill() operation not implemented for client %u\n", c->index);
+        return;
+    }
+
+    c->kill(c);
 }
 
 char *pa_client_list_to_string(struct pa_core *c) {
index ab7cb51..86ab572 100644 (file)
@@ -146,14 +146,14 @@ static int do_read(struct pa_ioline *l) {
         p = l->rbuf+l->rbuf_index;
         m = strlen(p);
 
-        if (l->callback)
-            l->callback(l, p, l->userdata);
-
         l->rbuf_index += m+1;
         l->rbuf_valid_length -= m+1;
 
         if (l->rbuf_valid_length == 0)
             l->rbuf_index = 0;
+
+        if (l->callback)
+            l->callback(l, p, l->userdata);
     }
 
     return 0;
@@ -180,10 +180,10 @@ static void io_callback(struct pa_iochannel*io, void *userdata) {
     struct pa_ioline *l = userdata;
     assert(io && l);
     
-    if (!l->dead && do_read(l) < 0)
+    if (!l->dead && do_write(l) < 0)
         goto fail;
     
-    if (!l->dead && do_write(l) < 0)
+    if (!l->dead && do_read(l) < 0)
         goto fail;
     
     return;
index be75b37..f44a8d4 100644 (file)
@@ -10,8 +10,6 @@
 #include "module.h"
 #include "mainloop-signal.h"
 
-int pa_stdin_inuse = 0, pa_stdout_inuse = 0;
-
 static struct pa_mainloop *mainloop;
 
 static void signal_callback(void *id, int sig, void *userdata) {
diff --git a/src/main.h b/src/main.h
deleted file mode 100644 (file)
index 35333bb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef foomainhfoo
-#define foomainhfoo
-
-extern int pa_stdin_inuse, pa_stdout_inuse;
-
-#endif
index 4a1692e..7306ade 100644 (file)
@@ -2,27 +2,36 @@
 #include <assert.h>
 #include <unistd.h>
 
-#include "main.h"
 #include "module.h"
 #include "iochannel.h"
 #include "cli.h"
+#include "sioman.h"
+
+static void eof_cb(struct pa_cli*c, void *userdata) {
+    struct pa_module *m = userdata;
+    assert(c && m);
+
+    pa_module_unload_request(m->core, m);
+}
 
 int module_init(struct pa_core *c, struct pa_module*m) {
     struct pa_iochannel *io;
     assert(c && m);
 
-    if (pa_stdin_inuse || pa_stdout_inuse) {
+    if (pa_stdio_acquire() < 0) {
         fprintf(stderr, "STDIN/STDUSE already used\n");
         return -1;
     }
 
-    pa_stdin_inuse = pa_stdout_inuse = 1;
     io = pa_iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO);
     assert(io);
     pa_iochannel_set_noclose(io, 1);
 
     m->userdata = pa_cli_new(c, io);
     assert(m->userdata);
+
+    pa_cli_set_eof_callback(m->userdata, eof_cb, m);
+    
     return 0;
 }
 
@@ -30,6 +39,5 @@ void module_done(struct pa_core *c, struct pa_module*m) {
     assert(c && m);
 
     pa_cli_free(m->userdata);
-    assert(pa_stdin_inuse && pa_stdout_inuse);
-    pa_stdin_inuse = pa_stdout_inuse = 0;
+    pa_stdio_release();
 }
index 53ebb8b..79bf177 100644 (file)
@@ -39,6 +39,7 @@ struct pa_sink* pa_sink_new(struct pa_core *core, const char *name, int fail, co
     s->monitor_source = pa_source_new(core, n, 0, spec);
     assert(s->monitor_source);
     free(n);
+    s->monitor_source->monitor_of = s;
     
     s->volume = PA_VOLUME_NORM;
 
diff --git a/src/sioman.c b/src/sioman.c
new file mode 100644 (file)
index 0000000..1a4b08b
--- /dev/null
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include "sioman.h"
+
+static int stdio_inuse = 0;
+
+int pa_stdio_acquire(void) {
+    if (stdio_inuse)
+        return -1;
+
+    stdio_inuse = 1;
+    return 0;
+}
+
+void pa_stdio_release(void) {
+    assert(stdio_inuse);
+    stdio_inuse = 0;
+} 
diff --git a/src/sioman.h b/src/sioman.h
new file mode 100644 (file)
index 0000000..e675c80
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef foosiomanhfoo
+#define foosiomanhfoo
+
+int pa_stdio_acquire(void);
+void pa_stdio_release(void);
+
+#endif
index 9a4f95a..1c97604 100644 (file)
@@ -26,6 +26,7 @@ struct pa_source* pa_source_new(struct pa_core *core, const char *name, int fail
     s->core = core;
     s->sample_spec = *spec;
     s->outputs = pa_idxset_new(NULL, NULL);
+    s->monitor_of = NULL;
 
     s->notify = NULL;
     s->userdata = NULL;
@@ -109,8 +110,12 @@ char *pa_source_list_to_string(struct pa_core *c) {
 
     default_source = pa_source_get_default(c);
     
-    for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index))
-        pa_strbuf_printf(s, "  %c index: %u, name: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name);
+    for (source = pa_idxset_first(c->sources, &index); source; source = pa_idxset_next(c->sources, &index)) {
+        char mo[256] = "";
+        if (source->monitor_of) 
+            snprintf(mo, sizeof(mo), ", monitor_of: <%u>", source->monitor_of->index);
+        pa_strbuf_printf(s, "  %c index: %u, name: <%s>%s\n", source == default_source ? '*' : ' ', source->index, source->name, mo);
+    }
     
     return pa_strbuf_tostring_free(s);
 }
index 03d540c..3b66cd3 100644 (file)
@@ -9,6 +9,7 @@ struct pa_source;
 #include "idxset.h"
 #include "memblock.h"
 #include "memchunk.h"
+#include "sink.h"
 
 struct pa_source {
     uint32_t index;
@@ -17,6 +18,7 @@ struct pa_source {
     struct pa_core *core;
     struct pa_sample_spec sample_spec;
     struct pa_idxset *outputs;
+    struct pa_sink *monitor_of;
 
     void (*notify)(struct pa_source*source);
     void *userdata;
index 1504381..505eeac 100644 (file)
--- a/src/todo
+++ b/src/todo
@@ -4,13 +4,10 @@
        more functions
 - simple library
 - kill() routines in all modules
-- command line protocol: 
-       kill client/input/output
-       default_sink/source
 - config parser/cmdline
 - move more stuff from module-oss[-dma] to liboss-util
-- stdin_inuse/stdout_inuse
 - svn-id and license in every file
+- in module-oss: create source first, than sink
 
 -- post 0.1
 - future cancellation