basic cli interface

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@22 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2004-06-18 00:22:37 +00:00
parent eb946dbdbe
commit 993d1bce74
21 changed files with 505 additions and 49 deletions

View file

@ -22,12 +22,25 @@ bin_PROGRAMS = polypaudio
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
@ -53,6 +66,14 @@ libpacket_la_LDFLAGS = -avoid-version
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
@ -68,3 +89,7 @@ module_oss_la_LIBADD = libiochannel.la liboss.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

83
src/cli.c Normal file
View file

@ -0,0 +1,83 @@
#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;
}

14
src/cli.h Normal file
View file

@ -0,0 +1,14 @@
#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

View file

@ -4,6 +4,7 @@
#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;
@ -42,3 +43,20 @@ void client_kill(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);
}

View file

@ -11,7 +11,6 @@ struct client {
const char *protocol_name;
void (*kill)(struct client *c);
void *userdata;
};
@ -24,4 +23,6 @@ void client_free(struct client *c);
* request destruction of the client */
void client_kill(struct client *c);
char *client_list_to_string(struct core *c);
#endif

View file

@ -50,30 +50,3 @@ void core_free(struct core *c) {
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;
}

View file

@ -15,7 +15,4 @@ struct core {
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

190
src/ioline.c Normal file
View file

@ -0,0 +1,190 @@
#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;
}

14
src/ioline.h Normal file
View file

@ -0,0 +1,14 @@
#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

View file

@ -9,6 +9,8 @@
#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");
@ -33,12 +35,12 @@ int main(int argc, char *argv[]) {
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);

6
src/main.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef foomainhfoo
#define foomainhfoo
extern int stdin_inuse, stdout_inuse;
#endif

34
src/module-cli.c Normal file
View file

@ -0,0 +1,34 @@
#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;
}

View file

@ -6,6 +6,7 @@
#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;
@ -110,3 +111,19 @@ void module_unload_all(struct core *c) {
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);
}

View file

@ -6,11 +6,6 @@
#include "core.h"
struct dependency_module {
lt_dlhandle dl;
struct dependency_module *next;
};
struct module {
struct core *core;
char *name, *argument;
@ -30,4 +25,6 @@ void module_unload_by_index(struct core *c, uint32_t index);
void module_unload_all(struct core *c);
char *module_list_to_string(struct core *c);
#endif

View file

@ -205,7 +205,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
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;
}
@ -224,7 +224,7 @@ static void on_connection(struct socket_server*s, struct iochannel *io, void *us
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;
}

View file

@ -5,6 +5,7 @@
#include "sink.h"
#include "sinkinput.h"
#include "strbuf.h"
#define MAX_MIX_CHANNELS 32
@ -214,3 +215,38 @@ uint32_t sink_get_latency(struct sink *s) {
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);
}

View file

@ -38,4 +38,10 @@ uint32_t sink_get_latency(struct sink *s);
void sink_notify(struct sink*s);
char *sink_list_to_string(struct core *core);
struct sink* sink_get_default(struct core *c);
#endif

View file

@ -5,6 +5,7 @@
#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;
@ -70,3 +71,37 @@ void source_post(struct source*s, struct memchunk *chunk) {
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);
}

View file

@ -29,4 +29,8 @@ void source_post(struct source*s, struct memchunk *b);
void source_notify(struct source *s);
char *source_list_to_string(struct core *c);
struct source* source_get_default(struct core *c);
#endif

View file

@ -1,6 +1,3 @@
#ifndef foostrbufhfoo
#define foostrbufhfoo
#include <sys/types.h>
#include <stdlib.h>
#include <assert.h>
@ -55,6 +52,14 @@ char *strbuf_tostring(struct strbuf *sb) {
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;
@ -118,5 +123,3 @@ int strbuf_printf(struct strbuf *sb, const char *format, ...) {
size *= 2;
}
}
#endif

View file

@ -6,6 +6,7 @@ struct strbuf;
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);