pkglib_LTLIBRARIES=libprotocol-simple.la module-simple-protocol-tcp.la \
libsocket-server.la module-pipe-sink.la libpstream.la libiochannel.la \
- libpacket.la module-oss.la module-oss-mmap.la liboss.la
+ libpacket.la module-oss.la module-oss-mmap.la liboss.la libioline.la \
+ libcli.la module-cli.la
+
+polypaudio_SOURCES = idxset.c idxset.h \
+ queue.c queue.h \
+ strbuf.c strbuf.h \
+ mainloop.c mainloop.h \
+ memblock.c memblock.h \
+ sample.c sample.h \
+ memblockq.c memblockq.h \
+ client.c client.h \
+ core.c core.h \
+ main.c main.h \
+ sourceoutput.c sourceoutput.h \
+ sinkinput.c sinkinput.h \
+ source.c source.h \
+ sink.c sink.h \
+ module.c module.h
-polypaudio_SOURCES = idxset.c queue.c strbuf.c mainloop.c \
- memblock.c sample.c memblockq.c client.c \
- core.c main.c sourceoutput.c sinkinput.c source.c sink.c \
- module.c
polypaudio_INCLUDES = $(INCLTDL)
polypaudio_LDADD = $(LIBLTDL)
polypaudio_LDFLAGS=-export-dynamic
liboss_la_SOURCES = oss.c
liboss_la_LDFLAGS = -avoid-version
+libioline_la_SOURCES = ioline.c
+libioline_la_LDFLAGS = -avoid-version
+libioline_la_LIBADD = libiochannel.la
+
+libcli_la_SOURCES = cli.c
+libcli_la_LDFLAGS = -avoid-version
+libcli_la_LIBADD = libiochannel.la libioline.la
+
module_simple_protocol_tcp_la_SOURCES = module-simple-protocol-tcp.c
module_simple_protocol_tcp_la_LDFLAGS = -module -avoid-version
module_simple_protocol_tcp_la_LIBADD = libprotocol-simple.la libiochannel.la
module_oss_mmap_la_SOURCES = module-oss-mmap.c
module_oss_mmap_la_LDFLAGS = -module -avoid-version
module_oss_mmap_la_LIBADD = libiochannel.la liboss.la
+
+module_cli_la_SOURCES = module-cli.c
+module_cli_la_LDFLAGS = -module -avoid-version
+module_cli_la_LIBADD = libcli.la libiochannel.la
--- /dev/null
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "ioline.h"
+#include "cli.h"
+#include "module.h"
+#include "sink.h"
+#include "source.h"
+#include "client.h"
+
+struct cli {
+ struct core *core;
+ struct ioline *line;
+
+ void (*eof_callback)(struct cli *c, void *userdata);
+ void *userdata;
+};
+
+static void line_callback(struct ioline *line, const char *s, void *userdata);
+
+struct cli* cli_new(struct core *core, struct iochannel *io) {
+ struct cli *c;
+ assert(io);
+
+ c = malloc(sizeof(struct cli));
+ assert(c);
+ c->core = core;
+ c->line = ioline_new(io);
+ assert(c->line);
+
+ c->userdata = NULL;
+ c->eof_callback = NULL;
+
+ ioline_set_callback(c->line, line_callback, c);
+ ioline_puts(c->line, "Welcome to polypaudio!\n> ");
+
+ return c;
+}
+
+void cli_free(struct cli *c) {
+ assert(c);
+ ioline_free(c->line);
+ free(c);
+}
+
+static void line_callback(struct ioline *line, const char *s, void *userdata) {
+ struct cli *c = userdata;
+ char *t = NULL;
+ assert(line && c);
+
+ if (!s) {
+ fprintf(stderr, "CLI client exited\n");
+ if (c->eof_callback)
+ c->eof_callback(c, c->userdata);
+
+ return;
+ }
+
+ if (!strcmp(s, "modules"))
+ ioline_puts(line, (t = module_list_to_string(c->core)));
+ else if (!strcmp(s, "sources"))
+ ioline_puts(line, (t = source_list_to_string(c->core)));
+ else if (!strcmp(s, "sinks"))
+ ioline_puts(line, (t = sink_list_to_string(c->core)));
+ else if (!strcmp(s, "clients"))
+ ioline_puts(line, (t = client_list_to_string(c->core)));
+ else if (!strcmp(s, "exit")) {
+ assert(c->core && c->core->mainloop);
+ mainloop_quit(c->core->mainloop, -1);
+ } else if (*s)
+ ioline_puts(line, "Unknown command\n");
+
+ free(t);
+ ioline_puts(line, "> ");
+}
+
+void cli_set_eof_callback(struct cli *c, void (*cb)(struct cli*c, void *userdata), void *userdata) {
+ assert(c && cb);
+ c->eof_callback = cb;
+ c->userdata = userdata;
+}
--- /dev/null
+#ifndef fooclihfoo
+#define fooclihfoo
+
+#include "iochannel.h"
+#include "core.h"
+
+struct cli;
+
+struct cli* cli_new(struct core *core, struct iochannel *io);
+void cli_free(struct cli *cli);
+
+void cli_set_eof_callback(struct cli *cli, void (*cb)(struct cli*c, void *userdata), void *userdata);
+
+#endif
#include <string.h>
#include "client.h"
+#include "strbuf.h"
struct client *client_new(struct core *core, const char *protocol_name, char *name) {
struct client *c;
c->kill(c);
}
+char *client_list_to_string(struct core *c) {
+ struct strbuf *s;
+ struct client *client;
+ uint32_t index = IDXSET_INVALID;
+ assert(c);
+
+ s = strbuf_new();
+ assert(s);
+
+ strbuf_printf(s, "%u client(s).\n", idxset_ncontents(c->clients));
+
+ for (client = idxset_first(c->clients, &index); client; client = idxset_next(c->clients, &index))
+ strbuf_printf(s, " index: %u, name: <%s>, protocol_name: <%s>\n", client->index, client->name, client->protocol_name);
+
+ return strbuf_tostring_free(s);
+}
+
const char *protocol_name;
void (*kill)(struct client *c);
-
void *userdata;
};
* request destruction of the client */
void client_kill(struct client *c);
+char *client_list_to_string(struct core *c);
+
#endif
free(c);
};
-struct sink* core_get_default_sink(struct core *c) {
- struct sink *sink;
- assert(c);
-
- if ((sink = idxset_get_by_index(c->sinks, c->default_sink_index)))
- return sink;
-
- if (!(sink = idxset_first(c->sinks, &c->default_sink_index)))
- return NULL;
-
- fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index);
- return sink;
-}
-
-struct source* core_get_default_source(struct core *c) {
- struct source *source;
- assert(c);
-
- if ((source = idxset_get_by_index(c->sources, c->default_source_index)))
- return source;
-
- if (!(source = idxset_first(c->sources, &c->default_source_index)))
- return NULL;
-
- fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index);
- return source;
-}
struct core* core_new(struct mainloop *m);
void core_free(struct core*c);
-struct sink* core_get_default_sink(struct core *c);
-struct source* core_get_default_source(struct core *c);
-
#endif
--- /dev/null
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ioline.h"
+
+#define BUFFER_LIMIT (64*1024)
+#define READ_SIZE (1024)
+
+struct ioline {
+ struct iochannel *io;
+ int dead;
+
+ char *wbuf;
+ size_t wbuf_length, wbuf_index, wbuf_valid_length;
+
+ char *rbuf;
+ size_t rbuf_length, rbuf_index, rbuf_valid_length;
+
+ void (*callback)(struct ioline*io, const char *s, void *userdata);
+ void *userdata;
+};
+
+static void io_callback(struct iochannel*io, void *userdata);
+static int do_write(struct ioline *l);
+
+struct ioline* ioline_new(struct iochannel *io) {
+ struct ioline *l;
+ assert(io);
+
+ l = malloc(sizeof(struct ioline));
+ assert(l);
+ l->io = io;
+ l->dead = 0;
+
+ l->wbuf = NULL;
+ l->wbuf_length = l->wbuf_index = l->wbuf_valid_length = 0;
+
+ l->rbuf = NULL;
+ l->rbuf_length = l->rbuf_index = l->rbuf_valid_length = 0;
+
+ l->callback = NULL;
+ l->userdata = NULL;
+
+ iochannel_set_callback(io, io_callback, l);
+
+ return l;
+}
+
+void ioline_free(struct ioline *l) {
+ assert(l);
+ iochannel_free(l->io);
+ free(l->wbuf);
+ free(l->rbuf);
+ free(l);
+}
+
+void ioline_puts(struct ioline *l, const char *c) {
+ size_t len;
+ assert(l && c);
+
+ len = strlen(c);
+ if (len > BUFFER_LIMIT - l->wbuf_valid_length)
+ len = BUFFER_LIMIT - l->wbuf_valid_length;
+
+ if (!len)
+ return;
+
+ if (len > l->wbuf_length - l->wbuf_valid_length) {
+ size_t n = l->wbuf_valid_length+len;
+ char *new = malloc(n);
+ if (l->wbuf) {
+ memcpy(new, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
+ free(l->wbuf);
+ }
+ l->wbuf = new;
+ l->wbuf_length = n;
+ l->wbuf_index = 0;
+ } else if (len > l->wbuf_length - l->wbuf_valid_length - l->wbuf_index) {
+ memmove(l->wbuf, l->wbuf+l->wbuf_index, l->wbuf_valid_length);
+ l->wbuf_index = 0;
+ }
+
+ memcpy(l->wbuf+l->wbuf_index+l->wbuf_valid_length, c, len);
+ l->wbuf_valid_length += len;
+
+ do_write(l);
+}
+
+void ioline_set_callback(struct ioline*l, void (*callback)(struct ioline*io, const char *s, void *userdata), void *userdata) {
+ assert(l && callback);
+ l->callback = callback;
+ l->userdata = userdata;
+}
+
+static int do_read(struct ioline *l) {
+ ssize_t r;
+ size_t m, len;
+ char *p, *e;
+ assert(l);
+
+ if (!iochannel_is_readable(l->io))
+ return 0;
+
+ len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
+
+ if (len < READ_SIZE) {
+ size_t n = l->rbuf_valid_length+READ_SIZE;
+
+ if (n >= BUFFER_LIMIT)
+ n = BUFFER_LIMIT;
+
+ if (l->rbuf_length >= n) {
+ if (l->rbuf_valid_length)
+ memmove(l->rbuf, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
+ } else {
+ char *new = malloc(n);
+ if (l->rbuf_valid_length)
+ memcpy(new, l->rbuf+l->rbuf_index, l->rbuf_valid_length);
+ free(l->rbuf);
+ l->rbuf = new;
+ l->rbuf_length = n;
+ }
+
+ l->rbuf_index = 0;
+ }
+
+ len = l->rbuf_length - l->rbuf_index - l->rbuf_valid_length;
+
+ if ((r = iochannel_read(l->io, l->rbuf+l->rbuf_index+l->rbuf_valid_length, len)) <= 0)
+ return -1;
+
+ e = memchr(l->rbuf+l->rbuf_index+l->rbuf_valid_length, '\n', r);
+ l->rbuf_valid_length += r;
+
+ if (!e && l->rbuf_valid_length >= BUFFER_LIMIT)
+ e = l->rbuf+BUFFER_LIMIT-1;
+
+ *e = 0;
+ 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;
+
+ return 0;
+}
+
+static int do_write(struct ioline *l) {
+ ssize_t r;
+ assert(l);
+
+ if (!l->wbuf_valid_length || !iochannel_is_writable(l->io))
+ return 0;
+
+ if ((r = iochannel_write(l->io, l->wbuf+l->wbuf_index, l->wbuf_valid_length)) < 0)
+ return -1;
+
+ l->wbuf_valid_length -= r;
+ if (l->wbuf_valid_length == 0)
+ l->wbuf_index = 0;
+
+ return 0;
+}
+
+static void io_callback(struct iochannel*io, void *userdata) {
+ struct ioline *l = userdata;
+ assert(io && l);
+
+ if (!l->dead && do_read(l) < 0)
+ goto fail;
+
+ if (!l->dead && do_write(l) < 0)
+ goto fail;
+
+ return;
+
+fail:
+ if (l->callback)
+ l->callback(l, NULL, l->userdata);
+ l->dead = 1;
+}
--- /dev/null
+#ifndef fooiolinehfoo
+#define fooiolinehfoo
+
+#include "iochannel.h"
+
+struct ioline;
+
+struct ioline* ioline_new(struct iochannel *io);
+void ioline_free(struct ioline *l);
+
+void ioline_puts(struct ioline *s, const char *c);
+void ioline_set_callback(struct ioline*io, void (*callback)(struct ioline*io, const char *s, void *userdata), void *userdata);
+
+#endif
#include "mainloop.h"
#include "module.h"
+int stdin_inuse = 0, stdout_inuse = 0;
+
static void signal_callback(struct mainloop_source *m, int sig, void *userdata) {
mainloop_quit(mainloop_source_get_mainloop(m), -1);
fprintf(stderr, "main: got signal.\n");
module_load(c, "module-oss-mmap", "/dev/dsp1");
module_load(c, "module-pipe-sink", NULL);
module_load(c, "module-simple-protocol-tcp", NULL);
+ module_load(c, "module-cli", NULL);
fprintf(stderr, "main: mainloop entry.\n");
while (mainloop_iterate(m, 1) == 0);
/* fprintf(stderr, "main: %u blocks\n", n_blocks);*/
fprintf(stderr, "main: mainloop exit.\n");
-
mainloop_run(m);
--- /dev/null
+#ifndef foomainhfoo
+#define foomainhfoo
+
+extern int stdin_inuse, stdout_inuse;
+
+#endif
--- /dev/null
+#include <stdio.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "main.h"
+#include "module.h"
+#include "iochannel.h"
+#include "cli.h"
+
+int module_init(struct core *c, struct module*m) {
+ struct iochannel *io;
+ assert(c && m);
+
+ if (stdin_inuse || stdout_inuse) {
+ fprintf(stderr, "STDIN/STDUSE already used\n");
+ return -1;
+ }
+
+ stdin_inuse = stdout_inuse = 1;
+ io = iochannel_new(c->mainloop, STDIN_FILENO, STDOUT_FILENO);
+ assert(io);
+
+ m->userdata = cli_new(c, io);
+ assert(m->userdata);
+ return 0;
+}
+
+void module_done(struct core *c, struct module*m) {
+ assert(c && m);
+
+ cli_free(m->userdata);
+ assert(stdin_inuse && stdout_inuse);
+ stdin_inuse = stdout_inuse = 0;
+}
#include <errno.h>
#include "module.h"
+#include "strbuf.h"
struct module* module_load(struct core *c, const char *name, const char *argument) {
struct module *m = NULL;
c->modules = NULL;
}
+char *module_list_to_string(struct core *c) {
+ struct strbuf *s;
+ struct module *m;
+ uint32_t index = IDXSET_INVALID;
+ assert(c);
+
+ s = strbuf_new();
+ assert(s);
+
+ strbuf_printf(s, "%u module(s) loaded.\n", idxset_ncontents(c->modules));
+
+ for (m = idxset_first(c->modules, &index); m; m = idxset_next(c->modules, &index))
+ strbuf_printf(s, " index: %u, name: <%s>, argument: <%s>\n", m->index, m->name, m->argument);
+
+ return strbuf_tostring_free(s);
+}
#include "core.h"
-struct dependency_module {
- lt_dlhandle dl;
- struct dependency_module *next;
-};
-
struct module {
struct core *core;
char *name, *argument;
void module_unload_all(struct core *c);
+char *module_list_to_string(struct core *c);
+
#endif
struct source *source;
size_t l;
- if (!(source = core_get_default_source(p->core))) {
+ if (!(source = source_get_default(p->core))) {
fprintf(stderr, "Failed to get default source.\n");
goto fail;
}
struct sink *sink;
size_t l;
- if (!(sink = core_get_default_sink(p->core))) {
+ if (!(sink = sink_get_default(p->core))) {
fprintf(stderr, "Failed to get default sink.\n");
goto fail;
}
#include "sink.h"
#include "sinkinput.h"
+#include "strbuf.h"
#define MAX_MIX_CHANNELS 32
return s->get_latency(s);
}
+
+struct sink* sink_get_default(struct core *c) {
+ struct sink *sink;
+ assert(c);
+
+ if ((sink = idxset_get_by_index(c->sinks, c->default_sink_index)))
+ return sink;
+
+ if (!(sink = idxset_first(c->sinks, &c->default_sink_index)))
+ return NULL;
+
+ fprintf(stderr, "core: default sink vanished, setting to %u.\n", sink->index);
+ return sink;
+}
+
+char *sink_list_to_string(struct core *c) {
+ struct strbuf *s;
+ struct sink *sink, *default_sink;
+ uint32_t index = IDXSET_INVALID;
+ assert(c);
+
+ s = strbuf_new();
+ assert(s);
+
+ strbuf_printf(s, "%u sink(s) available.\n", idxset_ncontents(c->sinks));
+
+ default_sink = sink_get_default(c);
+
+ for (sink = idxset_first(c->sinks, &index); sink; sink = idxset_next(c->sinks, &index)) {
+ assert(sink->monitor_source);
+ strbuf_printf(s, " %c index: %u, name: <%s>, volume: <0x%02x>, latency: <%u usec>, monitor_source: <%u>\n", sink == default_sink ? '*' : ' ', sink->index, sink->name, (unsigned) sink->volume, sink_get_latency(sink), sink->monitor_source->index);
+ }
+
+ return strbuf_tostring_free(s);
+}
void sink_notify(struct sink*s);
+char *sink_list_to_string(struct core *core);
+
+struct sink* sink_get_default(struct core *c);
+
+
+
#endif
#include "source.h"
#include "sourceoutput.h"
+#include "strbuf.h"
struct source* source_new(struct core *core, const char *name, const struct sample_spec *spec) {
struct source *s;
idxset_foreach(s->outputs, do_post, chunk);
}
+
+struct source* source_get_default(struct core *c) {
+ struct source *source;
+ assert(c);
+
+ if ((source = idxset_get_by_index(c->sources, c->default_source_index)))
+ return source;
+
+ if (!(source = idxset_first(c->sources, &c->default_source_index)))
+ return NULL;
+
+ fprintf(stderr, "core: default source vanished, setting to %u.\n", source->index);
+ return source;
+}
+
+char *source_list_to_string(struct core *c) {
+ struct strbuf *s;
+ struct source *source, *default_source;
+ uint32_t index = IDXSET_INVALID;
+ assert(c);
+
+ s = strbuf_new();
+ assert(s);
+
+ strbuf_printf(s, "%u source(s) available.\n", idxset_ncontents(c->sources));
+
+ default_source = source_get_default(c);
+
+ for (source = idxset_first(c->sources, &index); source; source = idxset_next(c->sources, &index))
+ strbuf_printf(s, " %c index: %u, name: <%s>\n", source == default_source ? '*' : ' ', source->index, source->name);
+
+ return strbuf_tostring_free(s);
+}
+
void source_notify(struct source *s);
+char *source_list_to_string(struct core *c);
+
+struct source* source_get_default(struct core *c);
+
#endif
-#ifndef foostrbufhfoo
-#define foostrbufhfoo
-
#include <sys/types.h>
#include <stdlib.h>
#include <assert.h>
return t;
}
+char *strbuf_tostring_free(struct strbuf *sb) {
+ char *t;
+ assert(sb);
+ t = strbuf_tostring(sb);
+ strbuf_free(sb);
+ return t;
+}
+
void strbuf_puts(struct strbuf *sb, const char *t) {
struct chunk *c;
size_t l;
size *= 2;
}
}
-
-#endif
struct strbuf *strbuf_new(void);
void strbuf_free(struct strbuf *sb);
char *strbuf_tostring(struct strbuf *sb);
+char *strbuf_tostring_free(struct strbuf *sb);
int strbuf_printf(struct strbuf *sb, const char *format, ...);
void strbuf_puts(struct strbuf *sb, const char *t);